image

When you create an ASP.NET Web Forms project using the default template, the web.config file specifies where users will “Log In” to the site.

Code Snippet
  1. <authentication mode=Forms>
  2.   <forms loginUrl=~/Account/Login.aspx timeout=2880 />
  3. </authentication>

The template also provides the “Account” directory as seen in the Visual Studio Explorer snapshot above.

Note that the “Account” contains it’s own web.config file which contains the following elements.

Code Snippet
  1. <?xml version=1.0?>
  2. <configuration>
  3.  
  4.   <location path=Register.aspx>
  5.     <system.web>
  6.       <authorization>
  7.         <allow users=*/>
  8.       </authorization>
  9.     </system.web>
  10.   </location>
  11.  
  12.   <system.web>
  13.     <authorization>
  14.       <deny users=?/>
  15.     </authorization>
  16.   </system.web>
  17.  
  18. </configuration>

The Login.aspx page is accessible to all users because it is specified as the LoginUrl for user authentication.

The web.config file is evaluated top-to-bottom.

The authorization element explicitly denies access to all UNAUTHENTICATED users by way of the specification <deny users=”?” /> where the question mark means all unauthenticated users.

However, if the user does not have an account on the web site, they will need access to the “Register.aspx” page in order to create one.

This resources specific access is provided via the <location> element which explicitly grants access to the “Register.aspx” page with the <allow users=”*”  /> where the star means all users, authenticated or not.

All this means that whenever a resource (page / directory) is requested but the user lack the necessary privileges for that resource, the user is redirected to the loginUrl specified in the application’s default web.config file.

In the default ASP.NET Web Forms template this works fine because the only authorization criteria is Logged In or NOT Logged In.

But what if our Authorization criteria is more diverse than that.

ASP.NET Membership makes it easy to configure URL based Authorization based on “ASP.NET Roles” or even for a specific user.

In the snapshot above showing solution in the Visual Studio Solution Explorer, please note 2 new directories.

  1. Admin
  2. SuperUser

The “Admin” folder will contain pages that implement administrative features for our web site, so we need to restrict access so that a user must be BOTH logged in AND a member of the “Administrator” Role Group in order to access the folders contained pages.

Our ”Admin” folder contains a web.config file with a defaul authorization critera that denies access to all users and then specifically GRANTS access to administrators with the element “<allow roles=”Administrator” />

Note that I have also granted access for ALL USERS to the page “AccessDenied.aspx”

Code Snippet
  1. <?xml version=1.0?>
  2. <configuration>
  3.     <location path=AccessDenied.aspx>
  4.         <system.web>
  5.             <authorization>
  6.                 <allow users=*/>
  7.             </authorization>
  8.         </system.web>
  9.     </location>
  10.   <system.web>
  11.     <authorization>       
  12.        <allow roles=Administrator/>  
  13.        <deny users=*/>      
  14.     </authorization>
  15.   </system.web>
  16. </configuration>

This creates an additional user experience challenge for us since a user can be logged in but NOT an Administrator. By default, when Authorization fails for any resource the user is redirected to the loginUrl.

This will be confusing for the user since they are already logged in, they just aren’t part of the “Administrator” role.

To improve the user experience, we’ll add some code to the Load Event of the Login.aspx page to determine whether or not we got there because an already logged in user tried to access a resource in the “Admin”  folder.

If this is the case we’ll redirect them to the “Admin/AccessDenied.aspx” file which is accessible to all users on the web site.

Code Snippet
  1. using System;
  2. using System.Web;
  3. using System.Web.Security;
  4.  
  5. namespace NETOOPWF.Account
  6. {
  7.     public partial class Login : System.Web.UI.Page
  8.     {
  9.         protected void Page_Load(object sender, EventArgs e)
  10.         {
  11.             string test = System.Configuration.ConfigurationManager.AppSettings["SuperUser"];
  12.             if (Request.IsAuthenticated)
  13.             {
  14.                 string mp = HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]);
  15.                 if (mp != null)
  16.                 {
  17.                     mp = mp.ToLower();
  18.                     if (mp.IndexOf(“%2fadmin”) > -1)
  19.                     {
  20.                         Response.Redirect(“~/Admin/AccessDenied.aspx”);
  21.                     }
  22.                 }
  23.             }
  24.             RegisterHyperLink.NavigateUrl = “Register.aspx?ReturnUrl=” + HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]);
  25.         }
  26.     }
  27. }

Here’s the Pseudo Code for the logic :

  • Check is the user is already logged in. If Yes (Then we probably got here due to an unauthorized access attempt ) ……
  • Get a string that contains the relative path to the page that was requests.
  • Find out if the requested page is in the ”Admin” directory. If Yes ….
  • Send the user to the “/Admin/AccessDenied.aspx” page.

Now, if the user requests a resourse in the Admin folder and the user is anonymous then they will be presented with the Login Page.

If they are already logged in but NOT an Administrator, they will see this page.

SNAGHTML19704c8

Note that we can use the same process when implementing user specific authorization.

Note also the folder named “SuperUser” in the Solution Explorer

image

The web.config file in the ”SuperUser” folder contains looks like this.

Code Snippet
  1. <?xml version=1.0?>
  2. <configuration>
  3.     <location path=AccessDenied.aspx>
  4.         <system.web>
  5.             <authorization>
  6.                 <allow users=*/>
  7.             </authorization>
  8.         </system.web>
  9.     </location>
  10.   <system.web>
  11.     <authorization>      
  12.        <allow users=SuperUser/> 
  13.        <deny users=*/>     
  14.     </authorization>
  15.   </system.web>
  16. </configuration>

 

Note that instead of allowing users based on a role, as we did in the “Admin” folder, we deny access to everyone and then explicitly GRANT access to ONLY a specific user who’s User Name is “SuperUser”.

We also have an AccessDenied.aspx page in the “SuperUser” folder that is accessible to anyone.

Next we modify the “Login.aspx.cs” file as follows.

Code Snippet
  1. using System;
  2. using System.Web;
  3. using System.Web.Security;
  4.  
  5. namespace NETOOPWF.Account
  6. {
  7.     public partial class Login : System.Web.UI.Page
  8.     {
  9.         protected void Page_Load(object sender, EventArgs e)
  10.         {
  11.             string test = System.Configuration.ConfigurationManager.AppSettings["SuperUser"];
  12.             if (Request.IsAuthenticated)
  13.             {
  14.                 string mp = HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]);
  15.                 if (mp != null)
  16.                 {
  17.                     mp = mp.ToLower();
  18.                     if (mp.IndexOf(“%2fsuperuser”) > -1)
  19.                     {
  20.                         Response.Redirect(“~/SuperUser/AccessDenied.aspx”);
  21.                     }
  22.                     if (mp.IndexOf(“%2fadmin”) > -1)
  23.                     {
  24.                         Response.Redirect(“~/Admin/AccessDenied.aspx”);
  25.                     }
  26.                 }
  27.             }
  28.             RegisterHyperLink.NavigateUrl = “Register.aspx?ReturnUrl=” + HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]);
  29.         }
  30.     }
  31. }

Since any user who requests a page in the \SuperUser folder and is NOT User Name “SuperUser” will get redirected to the LogIn page we can check to see if the requested resource was in the SuperUser folder.

Since the user named “SuperUser” would have access to all the resources in that folder, we know that the request was directed here because the user was NOT “SuperUser” and therefore is not Authorized.

Then we just redirect the user to the “\SuperUser\AccessDenied.aspx”  page.

SNAGHTML1ad7b9d