Authentication problems in web app

Authentication problems in web app

Old forum URL: forums.lhotka.net/forums/t/1942.aspx


SonOfPirate posted on Monday, December 11, 2006

We are in the process of implementing a form of integrated security in our web app where we rely on the default IIS authentication ("Windows") to verify the user's credentials on the network then attempt to match-up the IIS-authenticated user against a list of valid users for the application.  When validated for the application, we are able to retrieve the appropriate group membership, roles, rights, etc. (semantics) for that user and we return a populated IPrincipal object.

We have put the following code into the Global.asax file.  It is slightly different from what is in the book because we are not using Forms Authentication.  Instead, as I mentioned, we rely on IIS to pre-authenticate the user then perform our custom authentication to complete validate the user.  If the user passes the IIS test but is not found in our database (i.e. they are a valid user on the network but not setup in the application), we set the current user to an unauthenticated user (Guest).

In Global.asax:

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    System.Security.Principal.IPrincipal principal;
 
    try
    {
        principal = (System.Security.Principal.IPrincipal)HttpContext.Current.Session["CurrentPrincipal"]'
    }
    catch
    {
        principal = null;
    }
   
    if (principal == null)
    {
        if (!SecurityManager.Authenticate())
            SecurityManager.Logout();
       
        HttpContext.Current.Session["CurrentPrincipal"] = ApplicationContext.User;
    }
    else
    {
        ApplicationContext.User = principal;
    }
}

This works great initially but ends up running about 6 times before the page actually loads and only the first call has a valid Session.  To prevent the Null exceptions, we added a condition at the beginning to ensure that HttpContext.Current and HttpContext.Current.Session are not null.  But, in the end the HttpContext.Current.User is reset on us by IIS so we end up getting the IIS authenticated user and our custom portion is ignored.  This was verified by accessing the page using an authenticated network user that was not setup in our application.  As expected, the first pass correctly attempted to authenticate the user, failed and saved our Guest user into Session.  But, none of the additional calls could retrieve this value from Session because they always failed the null condition and our application wound up making use of the "unauthenticated" IIS-supplied user instead.

Any ideas where this is going wrong?  Why is the AcquireRequestState event occurring multiple times?  Suggestions how to remedy?

Thx in advance.

 

 

JoeFallon1 replied on Tuesday, December 12, 2006

Pirate,

When I upgraded from ASP.NET 1.1 to 2.0 I ran into the same issue regarding extra firings of Global_AcquireRequestState. I always had 2 of them in 1.1 but now I have 3 of them. The 3rd one fails to contain the Session object so I added the same trap at the top to bail out when Session is Nothing.

My web app is capable of using Forms authentication and Windows authentication. It was not a very simple solution but it seems to do what you are asking about. For Windows, we get the token from IIS and read the username and split it into Domain and User strings. These credentials must exist in our DB - we use them to grab the unique UID in our DB (and skip the password because Windows handled it already) and then log the user in and give them a cookie.

We got a lot of good ideas from this article:

http://15seconds.com/issue/050203.htm

The key idea is that the ExternalAuthentication virtual directory needs to be under the main app virtual directory. It looks like you are trying to both things from the same virtual.

(If it was an easy setup I would post some code - but it is a rather ugly mess under the hood.)

Joe

 

 

SonOfPirate replied on Tuesday, December 12, 2006

Yea, I just came back online because I found the following blog article on the subject:

http://blogs.msdn.com/praveeny/archive/2006/11/26/asp-net-2-0-acquirerequeststate-fires-multiple-times.aspx

The article you mentioned does have some great content as well.

Turns out, or at least it appears, that the AcquireRequestState is fired for each resource that is requested from the server.  So, if you have embedded resources, javascript files, images (?), css (?), etc. this event will fire again.

What I don't understand - and maybe it is because of the different handlers used to process the different resources - is why Session is available only to the first request.  It is obvious that the HttpContext is reset between requests but since we can't get access to Session, there is no way to reset the current principal; therefore, when we get around to asking to the current user, we get the WindowsPrincipal instead of our custom one.

So, my thoughts are to move the login logic to another event but I'm not sure what would be appropriate.  Anyone who may know better, please advise.

Frankly, though, I am surprised no one else has run into this.  It sounds like the multiple executions is prevalent based on what triggers it.

 

RobKraft replied on Friday, March 30, 2007

I found the following blog that gives a little more insight into what is happening; and we implemented the solution they recommend with success:

http://blogs.msdn.com/praveeny/archive/2006/11/26/asp-net-2-0-acquirerequeststate-fires-multiple-times.aspx

if (HttpContext.Current.Request.Url.AbsoluteUri.Contains(".axd"))

{

   return;

}

Copyright (c) Marimer LLC