Saturday, February 23, 2008

Secure Pages

Here's a short one. Like most web applications, the one that I am working on right now has pages that only a subset of users should have access to (admin pages, for instance). We are using the built in ASP.NET authorization mechanism. When an authenticated user attempts to get to a page they shouldn't see, we would like to show a generic error message and do some logging on the server. It turns out that ASP.NET simply redirects the user to the configured login page.

So, the scenarios are currently like this:

Figure 1: Default authentication scenarios

What we would prefer is the following:

Figure 2: Desired authentication scenarios

I was unable to find a normal way to configure this. The hunting we did produced a few hits for handling the 403 HTTP code (Unauthorized). Actually no 400 codes get sent in this situation, so I played with it until I got a workable solution. Basically, I configured the forms loginUrl
to the error page. Then, in Global.asax, added some code to the PostAuthenticateRequest event handler to send an unauthenticated user back to the login page. Here are a few snippets.

<configuration>
<
system.web>
</
compilation>
<
authentication
mode="Forms">
<
forms
loginUrl="~/Unauthorized.aspx">
</
credentials>
</
forms>
</
authentication>
<
authorization>
<
deny
users="?"/>
</
authorization>
</
system.web>
<
location
path="Login.aspx">
<
system.web>
<
authorization>
<
allow
users="?"/>
</
authorization>
</
system.web>
</
location>
<
location
path="Admin.aspx">
<
system.web>
<
authorization>
<
allow
users="AdminGuy"/>
<
deny
users="*"/>
</
authorization>
</
system.web>
</
location>
</
configuration>

Listing 1: Portion of web.config


protected

void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{

int compare =

String.Compare(HttpContext.Current.Request.PhysicalPath
, Server.MapPath("~/Unauthorized.aspx"), true);



bool unauthenticated = ((HttpContext.Current.User == null)
(!HttpContext.Current.User.Identity.IsAuthenticated));



if ((compare == 0) && unauthenticated)
{
Response.Redirect("~/Login.aspx?" + HttpContext.Current.Request.QueryString);
}
}

Listing 2: Global.asax code

Here is a stripped down solution that demonstrates the idea.

No comments: