We've got a web application that we launched about two months ago. It uses Forms authentication with a sqlRoleProvider and a couple membership providers (ldap and a db). Sessions are set to timieout after 60 minutes of inactivity.
99% of the time logging in after session times out works fine. But we have a lot of users, and about 1% of the time (at least that's been reported) a user will timeout, get redirected to the login page, and when they attempt to login they just get redirected back to the login page with no error message. I've actually seen this happen once and was able to attempt the login over and over and I never got an error, just had the login page reload over and over and over again. Unfortunately I have never been able to reproduce this at my desk, so I have no idea what's causing it or how to resolve it.
Here's a couple more details:
I use log4net and log each time the user attempts to login, is successfully logged in, and each time the login page loads. When this happens the log shows something like:
2008-09-01 15:15:33,579  DEBUG Login Page Loaded
2008-09-01 15:15:34,745  DEBUG ActiveDirectoryConnector  - Attempt to validate 'shampton'
2008-09-01 15:15:34,933  DEBUG ActiveDirectoryConnector  - Successfully validated 'shampton'
2008-09-01 15:15:35,521  DEBUG Login Page Loaded
2008-09-01 15:15:38,457  DEBUG Login Page Loaded
2008-09-01 15:15:41,217  DEBUG Login Page Loaded
2008-09-01 15:15:43,454  DEBUG Login Page Loaded
And that's it. There's no indication of what might have gone wrong, and there's no unhandled exception thrown...
I've scoured my code and I don't redirect the user to the login page ANYWHERE. Obviously the login page is in my web.config, but nowhere else is it mentioned. So it seems that something is happening within the ASP.NET authentication system...?
I could really use some help - has anyone seen anything like this before? I'm out of troubleshooting ideas...
Thanks for the help!
Do you keep track of the asp.net performance counters? I'm wondering if there could be something interesting happening in there, such as repeated application recycling or audit errors. Looking about it, it seems like it may have to do with a certain proxy configuration... would that ring a bell?
Also, its a long shot, but do you call Session.Abandon anywhere in your code?
Interesting idea. Could be a proxy or firewall config, but I'm not sure how to troubleshoot that... We are going through a couple firewalls in our architecture (web server is in one place, db server in another and authentication in another and all protected behind firewalls). Would this happen to only individual users on an occasional basis if that were the case?
The other thing you mentioned, calling Session.Abandon, sounds even more likely. I am calling it in only one place in the entire app, in the Session_End method of Global.asax.cs. So if, for some reason, the app kills the session right after they log in, then that might be the cause, but it does seem pretty strange. Again, they do log in successfully once, and this happens after they've timed out...
Does that help narow things down at all? I've put some debug lines in the Session_End so I can see if that's what's happening, but I won't be able to actually get that out there for testing until the next production build...
Thanks for the reply!
Yes actually. Doing a Session.Abandon in Session End is not very useful. Think about it: First, Session_End doesn't happen if you don't use InProc session. Don't know if thats your case or not. Second, when the session end... the session is lost. I beleive, too, that session end happens -after- the session is lost...so in rare scenarios where the session is lost, and the login redirection checks the authentication cookie, which is still present, it would push the sliding expiration (or some similar concept) and let the cookie still be valid, but the session.abandon would kick in, making the association invalid, over and over.
Anyway, the above is the single worse explaination in the history of information technology, so don't quote me (I'm not writing a book anytime soon, but as an excuse, english is far, far from being my primary language), but basically, Session.Abandon in the ONE event where you know for sure that session will vanish, is pretty much NOT useful...try and take it out. I confirmed before posting this that many people on the net had your exact issue, and it was related to session.abandon...nothing to lose eh?
Looks like its a similar situation to when people try and reload the cache in the event where cache expires... it ends up doing weird things.
Yeah, we're actually using StateServer for Session managemen, if that makes any difference...
I think I added Session.Abandon to Session_End a while back because we track a lot of info in the session, and I was finding that sometimes when the user's session had timed out, some of the session data was still there - it didn't trash all of the session objects. But I will comment it out and see if that fixes this issue. Sounds like that may be it...
Thanks again - eddie
If you're using StateServer, Session_End never happens as far as I know... so it may not be your problem... but its worth trying.
If session objects are still around after a session timeout (careful: session and login timeout separately...don't confuse one with the other.), there may be some stuff being done where you should not, of the same nature as the Session_End's session abandon... maybe thats worth investigating, too.
Really!? I didn't know that... Any idea if there's a link somewhere that mentions that? I did a search on MS KB and couldn't find much info at all on the specifics of each type of state management...
Here you go. Session End is an event from the http module SessionStateModule, and is handled specifically in Global.asax under various names (like for page events) and whatsnot... if you look at that page, its quite specific:
The Session_OnEnd event is only supported when the session-state HttpSessionState..::.Mode property value is InProc, which is the default. If the session-state Mode is set to StateServer or SQLServer, then the Session_OnEnd event in the Global.asax file is ignored. If the session state Mode property value is Custom, then support for the Session_OnEnd event is determined by the custom session-state store provider.
Yep, that's pretty clear! So this may not be it at all, but I've gone ahead and taken the line out anyways, since it shouldn't have any affect regardless. I've got in QA and am testing it, but it looks like we're back at square one again...
So I guess I'll try to find out what proxy or firewall configurations may be causing this, since I can't think of anything else...
Thanks again for your help!!
If you're using standard login procedures (either the AD Membership provider, or you're using the appropriate methods and events to implement your own, as opposed to an ad hoc solution), you can try implementing Health Monitoring to track what the hell is happening, by monitoring the audit events... That may enlighten you. Honestly, googling around, it seems to be an issue happening to multiple people... so I'm definately curious about the solution... it may hit -me- someday :)
One thing by the way that may be troublesome... How -exactly- are you redirecting the user to the login on a session timeout? Remember... when session timeout, the user may already be logged in... Depending on how your login system works, you may end up redirecting to login page someone that is already logged in... You're using global.asax or an http module to check the session's status? Have you investigated the redirect code and how it works? Do you log out the user? I'm wondering if there isn't a slight, uncommon logistic mistake in there...
I have no code in my application that actually redirects the user to the login page. I just have the login page noted in the web.config, and when the session doesn't exist I believe asp.net redirects them to the login page for me. Isn't that how it's supposed to work?
I found a good how-to on MSDN about health monitoring, so I'll try to put that in place and see if that doesn't pinpoint what's happening here. I'll definitely post back to this thread if I find more info, or better yet, the source and solution to this issue...
You'll get redirected to login if the login expires, which is quite different from if the session expires. Session can expire independently from authentication...
Thats a good link, and it has a link itself to a KB.
If you're never handling session timeout directly, things can get seriously quirky. A logged out user could still have session values from when they were logged in, before their authentication expired, and a logged in user could lose session... And they can easily get out of sync. I tend to redirect users to login if some session value isn't found, and in the login page, hit session.abandon if session still has values in it (if they went to the login page manually), as well as log them out, among other measures.
I think we may have a lead here now.
Yeah, I don't think I made the connection that session is completely separate from authentication... For some reason I've just been lumping them together. This could definitely be a lead. I'll re-read that article and the linked kb and see if I can make some code changes based on that. His suggested solution may work for us (make the authentication timeout double the session timeout and add that method to Global.asax.cs... I'll post back here if I get anywhere with this...