locked
Detecting App Pool recycle and handling user authentication RRS feed

  • Question

  • Hi,

    I host my Silverlight Application with an external hoster and as such I do not have control over when the app pool is recycled.

    Obviously when this happens, users currently logged in are no longer authenticated once the app pool restarts. This is of course different from a timout as the user may be in the middle of somthing when the recycle occurs so I would like to somehow silently log the user back in so that they are not affected by the app pool recycle. But I am not sure if this is A) possible or B) how to go about it.

    I have my RIA services secured with the [RequiresAuthentication] attribute so any attempt to access them by an unauthenticated user returns an exception. If the answer is to check that the user is authenticated before every call to a service how would this work in the scenario where there is a datapager and domaindatasource combination and the call to the servcie is controlled entierly through XAML? 

    Obviously I am looking for the easiest solution here ideally without the need to modify every pice of code that makes a call to the server, but any information would be usefull.

    Tuesday, July 6, 2010 2:56 PM

Answers

  • So the general security concern with storing usernames and passwords on the client in memory is that someone might be able to read them from memory at a later point. I can't speak to how valid this concern is, but obtaining the information would take a level of sophistication generally not applied to home computers and public terminals. I believe you can mitigate the concern by storing them in a character buffer and zeroing it out again (old school) on shutdown, but again I'm not terribly familiar with this threat. Also, do not persist these values on a client (in isolate storage, etc) as it introduces another layer of similar threats.

    Kyle

    Friday, July 9, 2010 7:03 PM

All replies

  • Hi!

    This is not exactly an answer, but here is what I usually do: In my callbacks and event handlers, first thing I do is let a static helper class run a check on the OperationBase parameter to see if an unauthorized access happened (i.e. if operation.Error is a DomainOperationException and whether its Status is OperationErrorStatus.Unauthorized). Depending on the result, I then decide what to do.

    Instead of a simple redirect to a login page or similar, an option probably would be to silently try to load the user again by invoking AuthenticationService.LoadUser(). If the user still has a valid authentication cookie, this will succeed.

    However, as you pointed out, this doesn't work in all cases (e.g. when the calls are controlled through XAML or built-in controls), and I imagine it's not a trivial task to correctly resume any failed operation after a silent login. If anyone has a simple and graceful solution to this, I'd also be happy to hear about it :).

    Also, do you use sessions on the server side? Because you lose that data too, and all the hard work on the client may be pointless when you don't have the user's session data anymore.

    Tuesday, July 6, 2010 5:29 PM
  • Hi,

    Thanks for the information, unfortunately I have a lot of instances where the connection is controlled by XAML and hence a lot of places where the user will still experience a problem when the app pool is recycled.

    In answer to your question about sessions; I don't explicitly use sessions server side to store any user data, so this should not be a problem. It is just the authentication issue.

    Wednesday, July 7, 2010 9:04 AM
  • It might be worth your while to look at the authorization sample I put together (http://blogs.msdn.com/b/kylemc/archive/2010/05/03/silverlight-authorization-sample.aspx). Specifically the TimeoutHelper classes are used to detect if the client authentication status has changed. In my scenario, I was testing cookie timeout, but session reset seems to be essentially the same challenge.

    Kyle

    Thursday, July 8, 2010 9:12 AM
  • Hi Kyle,

    I have been working through your sample and integrating it into my project, but it appears my scenario is sufficiently different for your TimeoutHelper not to apply in its current format;

    I have my Service secured with the [RequiresAuthentication] attribute. If my user's Authentication has timed out on the server, or the app pool has been recycled, when he makes the next call to the service I receive a 'DomainOperationException' rather than the 'DomainException' your code is expecting.

    I modified the code to cast the exception to a DomainOperationException and also modified the test for the exception.ErrorCode to look for '401' as this is the error code returned by the DomainOperationException in my application.

    When the code moves on to the 'WebContext.Current.Authentication.LoadUser(), rather than silently reloading the user and renewing the authentication status on the server the user on the client is logged out.

    For completeness and to more closely replicate your sample, I also tried with the [RequireAuthentication] attribute removed from the service and a [RequiresRole("Administrator")] attribute added to the particular query I am running. (The test user is in the role 'Administrator'), but I get the same behaviour as described above.

    Please could you explain why I am experiencing this behaviour and hopefully guide me to a resolution as I really like the theory of what your sample shows.

    Thursday, July 8, 2010 9:50 PM
  • Did you see that TimeoutHelper exists on both the client and server? The server side looks for a unauthenticated access and returns a special error code in a DomainException. The client side (which you've described) looks for that same error code to know when to refresh. Both sides are crucial to getting the theory working correctly.

    Kyle

    Friday, July 9, 2010 9:05 AM
  • Ah, I missed the 'OnError' override in the service definition. Adding it means the TimeoutHelper code functions as expected.

    But, I still have the problem that the when WebContext.Current.Authentication.LoadUser(); is called by the client side TimeoutHelper it actually just logs the user out clinet side.

    I know this because the WebContext.Current.Authentication.LoggedOut event fires and examining the User Iprincipal shows that IsAuthenticated = false.

    I was expecting the code to silently log the user back in without having to prompt for username and password so that I could attempt to run the requested operation again without the user noticing the timeout or app pool recycle had happened.

    Is this possibe? If so, why is the LoadUser method not logging the user back in?

    Friday, July 9, 2010 1:34 PM
  • Yes, responding to a timeout with a LoadUser() call can generate a Logout event. That arguably what you'd want in a timeout scenario (say you walked away from your computer and your malicious coworker wanted to use your account to send something hilarious, but also embarassing to the team; now the application re-prompts for credentials).

    You could do something other than call LoadUser, though. Perhaps if you had the valid user name and password stored you could just attempt to re-login. There are some security concerns holding that kind of thing in-memory, but they may or may not apply to your scenario.

    Also, you might be able to tell the difference between timeouts and cycling, communicate them in two different error codes and respond to each differently. I'm not sure how easy that would be, though. Whatever the case, you can modify the TimeoutHelper types to do what's most convenient for your application. 

    Kyle

    Friday, July 9, 2010 5:44 PM
  • Thanks for all your help with this Kyle.

    It is really the app pool cycling that I am worried about because as you say a timeout should prompt for user credentials. The problem is that the app pool can be cycled at any point by my hosting company and its possible a user is in the middle of something in the app at the time. Presenting a login box in this scenario would be a confusing user experience.

    If it were possible to detect the difference between a cycle and a timeout that would be useful but I don't know where to start with this as all I see is that the user is no longer authenticated on the server.

    Storing the user credentials may be the only way but the security issues you speak of worry me. My app is centrally hosted and the users login via the internet from their home machines. Could I store them securely on the client machine somehow?

    Friday, July 9, 2010 6:06 PM
  • So the general security concern with storing usernames and passwords on the client in memory is that someone might be able to read them from memory at a later point. I can't speak to how valid this concern is, but obtaining the information would take a level of sophistication generally not applied to home computers and public terminals. I believe you can mitigate the concern by storing them in a character buffer and zeroing it out again (old school) on shutdown, but again I'm not terribly familiar with this threat. Also, do not persist these values on a client (in isolate storage, etc) as it introduces another layer of similar threats.

    Kyle

    Friday, July 9, 2010 7:03 PM