I have a webserver from where users can download files that are specific for each user. To be sure each user can only download its own files they must authenticate via Basic-Authentication. So for each user there is a windows-account on the server that has read permissions to the user specific folder.
Now I want to move this functionality to another server. I do not want to create windows accounts for the users but still keep the Basic-Authentication. So I use the Custom Basic Authentication HTTP Module in combination with a Custom MembershipProvider that lets me define users in the web.config.
The authentication works quite fine but after logging in with either jack
or jill
(see web.config) I'm able to access both locations Dir1
and Dir2
. This is also the case if I comment out the <allow users="jack" />
part in the location tags.
Additional Info:
I created a Default.aspx file and added a
<% Response.Write(HTTPContext.Current.User.Identity.Name) %>
which returns the correct user name depending on who logged in.
<% Response.Write(HTTPContext.Current.User.Identity.IsAuthenticated) %>
returns True.
What do I have to do that only jack
is able to access (= download files from) Dir1
and only jill
is able to access (=download files from) Dir2
but not the other way round?
EDIT: I tried to add web.config files for each subdirectories instead of the location tags as mentioned by utkai - with the same result. Every user can access any directory.
Here is my Web.config file:
<configuration>
<system.webServer>
<modules>
<add name="CustomBasicAuthentication" type="LeastPrivilege.CustomBasicAuthentication.CustomBasicAuthenticationModule, LeastPrivilege.CustomBasicAuthenticationModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=F20DC168DFD54966"/>
</modules>
<security>
<authentication>
<customBasicAuthentication enabled="true" realm="TEST" providerName="AspNetWebConfigMembershipProvider" cachingEnabled="true" cachingDuration="15" requireSSL="false"/>
</authentication>
<authorization>
<deny users="?" />
</authorization>
</security>
</system.webServer>
<system.web>
<membership defaultProvider="AspNetWebConfigMembershipProvider">
<providers>
<add name="AspNetWebConfigMembershipProvider" type="LeastPrivilege.AspNetSecurity.Samples.WebConfigMembershipProvider, WebConfigMembershipProvider"/>
</providers>
</membership>
<authentication mode="Forms">
<forms>
<credentials passwordFormat="Clear">
<user name="jack" password="jack"/>
<user name="jill" password="jill"/>
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
</system.web>
<location path="Dir1" allowOverride="false">
<system.web>
<authorization>
<!-- <allow users="jack" /> -->
<deny users="*" />
</authorization>
</system.web>
</location>
<location path="Dir2" allowOverride="false">
<system.web>
<authorization>
<!-- <allow users="jill" /> -->
<deny users="*" />
</authorization>
</system.web>
</location>
</configuration>
Update #3
You can enable URLAuthorization to force IIS to protect files that aren't normally processed in IIS. The solution here depends on IIS 7.x and using Integrated pipelines.
<system.webServer>
<modules>
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
</modules>
</system.webServer>
Updated #2
You can switch entirely to Forms authentication only by removing the custom things you've added and do the following.
I've actually tested this and it only allows jack in to dir1 and jill in dir2. Both can access the root.
If this doesn't work, we'll need to discuss more of your setup.
web.config
<?xml version="1.0"?>
<configuration>
<system.webServer>
<modules>
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
</modules>
</system.webServer>
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="Default.aspx">
<credentials passwordFormat="Clear">
<user name="jack" password="jack" />
<user name="jill" password="jill" />
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
<compilation debug="true"></compilation>
<customErrors mode="Off"/>
</system.web>
<location path="dir1">
<system.web>
<authorization>
<allow users="jack" />
<deny users="*, ?" />
</authorization>
</system.web>
</location>
<location path="dir2">
<system.web>
<authorization>
<allow users="jill" />
<deny users="*, ?" />
</authorization>
</system.web>
</location>
</configuration>
Login.aspx - You must add in the redirect from the Login control because otherwise Forms authentication will look for a database in the App_Code directory, which doesn't exist.
<asp:Login ID="Login1" runat="server" OnAuthenticate="Login1_Authenticate">
</asp:Login>
Login.aspx.cs
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
string username = Login1.UserName;
string password = Login1.Password;
if (FormsAuthentication.Authenticate(username, password))
{
FormsAuthentication.RedirectFromLoginPage(username, false);
}
}
Update #1
I went through the example that you linked as Custom Basic Authentication HTTP Module and then followed through to The HTTP Module which has a link at the very bottom to additional source.
This source has a membership provider example using the custom basic authentication. I feel like you're running in to troubles by mixing in the Forms membership provider that you have in your web.config.
When you start to make your own separate authentication, things don't go nicely and you usually need to add in your own everything.
This code works from that additional link on my end.
As an added possibility, if you would like to let ASP.NET handle all of the membership itself and you are using SQL to store everything, consider looking at http://weblogs.asp.net/sukumarraju/archive/2009/10/02/installing-asp-net-membership-services-database-in-sql-server-expreess.aspx to see how to use the wizard to set it up in SQL.
The built in membership will be Forms authentication and be a lot less work than using custom.
Previous Version
I've never had luck with using the <location>
tags so I just put new web.configs in the directories. I've also had troubles when I don't exclude anonymous in sub folders as well. This seems to be that the browser will default to anonymous which will get through
Here is how I do it.
Root web.config
<system.web>
<authorization>
<allow roles="AccessRole1, AccessRole2" users="domain\jack, domain\jill"/>
<deny users="*, ?" /> <!-- make sure you deny anonymous with '?' -->
</authorization>
</system.web>
Sub directory web.config. Make sure you explicitly deny all other users. If you don't deny all other users, they can still get in.
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow users="domain\jill" />
<deny users="*, ?"/> <!-- explicitly deny all others, including anonymous -->
</authorization>
</system.web>
</configuration>
Here is a link to a good article with details to several situations, where one would want to allow/deny access to particular page or folder:
Setting authorization rules for a particular page or folder in web.config
As a side comment, in one project we do, we use the option of individual web.config file in each folder, as stated in the link as well, and it works for us just fine.
Hopefully, it helps to solve your problem.
this approach is similar but different - location is a file instead of a directory:
Is it possible to allow anonymous user to browse only few files from a folder
Use this step-by-step guide to apply the tag to the Web.config file to configure access to a specific file and folder.
<location path="default1.aspx">
<system.web>
<authorization>
<allow users ="*" />
</authorization>
</system.web>
</location>
<!-- This section gives the unauthenticated user access to all of the files that are stored in the Subdir1 folder. -->
<location path="subdir1">
<system.web>
<authorization>
<allow users="Admin" />
</authorization>
</system.web>
</location>
More info...
Set the following in your Web.config
<modules runAllManagedModulesForAllRequests="false">
Place the following event in your Global.asax
file.
protected void Application_BeginRequest(Object sender, EventArgs e)
{
}
Now whenever you type the URl like below.
http://localhost/dir1/jack.txt
The control will always move to Application_BeginRequest
event. You have Request.Url
information and Current User information
and you can do the validation here.
Using below code
throw new HttpException(403,"Acess Denied");
or send the user to some another page with some user friendly message.