Sliding sessions in WIF with the session authentication module (SAM) and Thinktecture IdentityModel
Session lifetime with WIF’s SAM (session authentication module), by default, is fixed, meaning that the session ends when the token lifetime ends. The logic to determine the session duration (and how to change it) was mentioned here. There is no automatic support for sliding sessions in WIF but it’s possible by handling the SAM’s SessionSecurityTokenReceived event which, when handled in global.asax, typically looks like this:
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e) { SessionAuthenticationModule sam = FederatedAuthentication.SessionAuthenticationModule; var token = e.SessionToken; var duration = token.ValidTo.Subtract(token.ValidFrom); if (duration <= TimeSpan.Zero) return; var diff = token.ValidTo.Add(sam.FederationConfiguration.IdentityConfiguration.MaxClockSkew).Subtract(DateTime.UtcNow); if (diff <= TimeSpan.Zero) return; var halfWay = duration.TotalMinutes / 2; var timeLeft = diff.TotalMinutes; if (timeLeft <= halfWay) { e.ReissueCookie = true; e.SessionToken = new SessionSecurityToken( token.ClaimsPrincipal, token.Context, DateTime.UtcNow, DateTime.UtcNow.Add(duration)) { IsPersistent = token.IsPersistent, IsReferenceMode = token.IsReferenceMode }; } }
The logic in this event handler will renew the session cookie if the duration remaining is less than half of the total session duration (much like forms authentication). For example, if the session duration is 30 minutes and the user has 15 minutes or less in the session, the session will be renewed. The above code, when issuing a new session security token, also honors some of the other details of session tokens including dealing with the allowable clock skew and preserving the prior token’s flags.
While it’s possible and fairly simply to include the above code in each of your projects if you’d like sliding session, it’s tedious. As such, this feature was added to the Thinktecture IdentityModel security library. It does need to be called from Init in global.asax, but it’s a one-liner:
public override void Init() { PassiveModuleConfiguration.EnableSlidingSessionExpirations(); }
HTH
I think that your sliding expiration is not quite right and the ValidTo will increase with the clock skew (5 minutes by default) every time it is renewed. The validTo parameter in the CreateSessionSecurityToken should just be DateTime.UtcNow.Add(token.ValidTo.Subtract(token.ValidFrom)).
HTH
Ah yes — good catch. I was overloading the semantics of the duration variable. Thx
So the more I think about it, I don’t think I even need the clock skew check on the duration (only on the ValidTo).
Hi, I’ve just come to implement this and without the clock skew on the duration the halfway amount isn’t calculated properly. The skew is factored into the session timeout amount, so the half way amount should as well.
I had a 10 second timeout (for test purposes) which highlighted the issue as the half way point time was 5 seconds, even though the session takes 5 minutes and 5 seconds to timeout.
So the renewal was happening at 5 seconds, not 2.5 mins? I guess I don’t see it as crucial for the sliding time to be at exactly 1/2 the session time, especially when normally the session is 1 hour to 10 hours, normally. *shrug*
2 1/2 seconds, so it just wasn’t being hit, because the chances of you hitting the server in that window are pretty slim.
Fair enough comment on it not needing to be exact, and I only hit the issue as I had a ridiculously short timeout window to test the functionality. We do have short session windows though (lowest is 10 minutes), so more likely to be an issue for us, but I’ve just changed it in our applications.
Thanks for the article, this was very helpful and saved me a lot of pain :-)
Glad it helped. If you feel that it’s worthwhile, feel free to submit a pull request for the code on github — that way everyone else can get the update.
Thx.
After issuing the new security token and setting the cookie accordingly the BootStrapToken serialized to the current claims Identity remains the old one, with the potentially expired token. This causes problems when trying to use the bootstrap context token for different reasons.
What is the best way to update the bootstrap token with the new issued token?
*I also posted the question here: http://stackoverflow.com/questions/21984380/updating-bootstrapcontext-with-new-sessionsecuritytoken-when-using-sliding-sessi
Please open an issue on the github issue tracker for the project. Thx.
Sliding expiration is a pretty nice thing to have, the algorithm of re-issuing a token only if it is expired half way is pretty smart. The downside of this solution seems to be that it uses sliding expiration IN STEAD OF absolute expiration. Now a token once issued can be extended unlimited. So once an attacker get a hold of a token it can keep on using it to generate new tokens as long as he refreshes it before it expires. This could be considered a serious security issue.
I would prefer a situation where there is both a sliding expiration (say 1 hour) and an absolute expiration (say 10 hours). This would require storing both the absolute and the sliding expiration times in the token. As the SessionToken only has a single ‘ValidTo’ property you might need to store the absolute expiration time in a custom claim in the principal.
Any other Idea how to solve this?