Global.asax - WindowsAuthentication_Authenticate - SessionState null and Multiple Cal

This is an internal application that uses windows authentication. In WindowsAuthentication_Authenticate method, i am getting the logged in user from the db. If the user is not found or marked as gone then i redirect the user to an error page.

1. WindowsAuthentication_Authenticate This method executes multiple times, including css or js files referenced in the head section.


[COLOR=blue]<[/COLOR][COLOR=maroon]link[/COLOR] [COLOR=red]href[/COLOR][COLOR=blue]=[/COLOR][COLOR=blue]"[/COLOR]@[COLOR=blue]Url[/COLOR][COLOR=blue].[/COLOR][COLOR=blue]Stylesheet[/COLOR][COLOR=blue]([/COLOR][COLOR=#a31515]"Layout.css"[/COLOR][COLOR=blue])"[/COLOR] [COLOR=red]rel[/COLOR][COLOR=blue]=[/COLOR][COLOR=blue]"stylesheet"[/COLOR] [COLOR=red]type[/COLOR][COLOR=blue]=[/COLOR][COLOR=blue]"text/css"[/COLOR] [COLOR=blue]/>[/COLOR] 
[COLOR=blue]<[/COLOR][COLOR=maroon]script[/COLOR] [COLOR=red]src[/COLOR][COLOR=blue]=[/COLOR][COLOR=blue]"[/COLOR]@[COLOR=blue]Url[/COLOR][COLOR=blue].[/COLOR][COLOR=blue]Script[/COLOR][COLOR=blue]([/COLOR][COLOR=#a31515]"Tools/extensions.js"[/COLOR][COLOR=blue])"[/COLOR] [COLOR=red]type[/COLOR][COLOR=blue]=[/COLOR][COLOR=blue]"text/javascript"[/COLOR][COLOR=blue]></[/COLOR][COLOR=maroon]script[/COLOR][COLOR=blue]>[/COLOR] 

In this case, if i have 3 style sheets and 2 js files referenced then this method executes 6 times.

2. Session State Null

Per problem # 1 above, i don’t want to hit DB multiple times. To work around it, i tried putting the user information in a session. Here i am getting HttpContext.Current.Session is null. In web.config i don’t have any configuration regarding session.

Here is my complete code…


 [COLOR=blue]protected[/COLOR] [COLOR=blue]void[/COLOR] WindowsAuthentication_Authenticate([COLOR=blue]object[/COLOR] sender, [COLOR=#2b91af]WindowsAuthenticationEventArgs[/COLOR] e)         
{                          [INDENT][COLOR=blue]bool[/COLOR] isUserFound = [COLOR=blue]false[/COLOR];             
[COLOR=blue]bool[/COLOR] isUserGone = [COLOR=blue]false[/COLOR];             
[COLOR=#2b91af]UtilityService[/COLOR] utility = [COLOR=blue]new[/COLOR][COLOR=#2b91af]UtilityService[/COLOR]();               
[COLOR=blue]string[/COLOR] rawurl = [COLOR=#2b91af]HttpContext[/COLOR].Current.Request.RawUrl;               
[COLOR=blue] if[/COLOR] (e.Identity.IsAuthenticated)             
{                 [INDENT][COLOR=blue]if[/COLOR] (userPlaceHolder == [COLOR=blue]null[/COLOR]) //local property to tackle hitting DB multiple times                 
{                     [INDENT][COLOR=#2b91af] UserInternal[/COLOR] userInternal = utility.GetLoggedInUser(e.Identity.Name);                     
[COLOR=blue]if[/COLOR] (userInternal != [COLOR=blue]null[/COLOR])                     
{                         [INDENT] userPlaceHolder = userInternal;                         
isUserFound = [COLOR=blue]true[/COLOR];                         
[COLOR=green]//TODO: check for gone, you can use userInternal or userPlaceHolder[/COLOR]  
isUserGone = [COLOR=blue]false[/COLOR];                     
[/INDENT]}                 
[/INDENT]}                 
[COLOR=blue]else[/COLOR]                 
{                     [INDENT] isUserFound = [COLOR=blue]true[/COLOR];                     
[COLOR=green]//TODO: check for gone, use userPlaceHolder[/COLOR]                     
isUserGone = [COLOR=blue]false[/COLOR];                 
[/INDENT]}             
[/INDENT]}                         
 [COLOR=green]//set the user[/COLOR]             
[COLOR=blue]if[/COLOR] (isUserFound && !isUserGone)             
{                 [INDENT][COLOR=blue]string[/COLOR] role = [COLOR=#2b91af]String[/COLOR].IsNullOrWhiteSpace(userPlaceHolder.UserClass) ? [COLOR=#2b91af]String[/COLOR].Empty : userPlaceHolder.UserClass;                 
[COLOR=green]// Setting the current user and role in the Principal[/COLOR]                 
e.User = [COLOR=blue]new[/COLOR] System.Security.Principal.[COLOR=#2b91af]GenericPrincipal[/COLOR](e.Identity, [COLOR=blue]new[/COLOR][COLOR=blue]string[/COLOR][] { role });                 
[COLOR=#2b91af]HttpContext[/COLOR].Current.User = e.User;             
[/INDENT]}               
[COLOR=green]//handle gone and user not found[/COLOR]             
[COLOR=blue]if[/COLOR] (!rawurl.LowerInvariantContains([COLOR=#2b91af]ControllerNames[/COLOR].Message) &&
!rawurl.LowerInvariantContains([COLOR=#a31515]".css"[/COLOR]) &&
!rawurl.LowerInvariantContains([COLOR=#a31515]".js"[/COLOR]) &&
!rawurl.LowerInvariantContains([COLOR=#a31515]".jpg"[/COLOR]) &&
!rawurl.LowerInvariantContains([COLOR=#a31515]".gif"[/COLOR]) &&
!rawurl.LowerInvariantContains([COLOR=#a31515]".png"[/COLOR]))             
{                 [INDENT][COLOR=blue]if[/COLOR] (!isUserFound || isUserGone)                 
{                     [INDENT][COLOR=blue]string[/COLOR] url = [COLOR=#2b91af]String[/COLOR].Empty;                     
[COLOR=blue]if[/COLOR] (isUserGone)                         
url = utility.GetSiteRestrictedLink([COLOR=#2b91af]ProcessingMessagesEnum[/COLOR].UserLocked);                     
[COLOR=blue]else[/COLOR]                         
url = utility.GetSiteRestrictedLink([COLOR=#2b91af]ProcessingMessagesEnum[/COLOR].UserNotAuthorizedToViewSite); ;                     
[COLOR=#2b91af] HttpContext[/COLOR].Current.Response.Redirect(url);                 
[/INDENT]}             
[/INDENT]}         
[/INDENT]}

Remember each request is a separate execution of the global context, hence the general advice to move static assets off to a separate server. So your windows auth calls make sense – your stylesheets and such are a request and windows auth is being performed.

Several ways around this, what are you trying to achieve here?

Basically,

I want to check the logged in user against the DB for the following two conditions

  1. user is in the employee db
  2. user is not marked as gone

If any of the above conditions is true then i want to redirect the user to the error page. (Active dir should handle this and user should not get authenticated at the first place. I am doing redundant checks, what if HR has updated the employee db but systems failed to update at their end).

Should i move the checking to application start since that executes only once? If yes, then how can i set the user:


// Setting the current user and role in the Principal                 
e.User = new System.Security.Principal.GenericPrincipal(e.Identity, newstring[] { role });                 
HttpContext.Current.User = e.User; 

I only want to hit the DB once in WindowsAuthentication_Authenticate.

Application start won’t work unless this is single instance. Session start might work since it is per-user, but I hate to rely upon sessions.

It is happening once per request, trick is your setup is running every request through .NET so each resource re-authenticate. Since HttpModules are global, that is how it rolls.

Easiest solution is probably to find a way to setup the static resources to not end up running through the .NET pipeline.

This process could be much simplified if you would use a login page where you do all the authentication things.

If you use a master page you can check authentication state. if not auth. redirect to login page.

Or you can use a httphandler for the redirect part that could do the checking job on every request.

This apps requirement is windows authentication and not the form.

I have some checks/traps in place now and testing.

wwb_99, looks like the request executes for css and js resources etc only on the local dev. Remote dev site is not doing this.

Well, that would help. Basically, IIS6 won’t, but IIS7 in integrated mode and/or cassini will execute all code through the managed pipeline.

My post #3 above has the details…

Application uses windows authentication.

At a central location, i want to make the checks specified in post#3.

I don’t want to handle this via base controller.