Nick Albrecht
Nick Albrecht

Reputation: 16928

Replace FormsAuthentication with SessionAuthenticationModule (SAM) to make Claims Aware identity

I have an existing MVC4 app (.NET 4.5) using FormsAuthentication that I'm looking to switch to using SessionAuthenticationModule so that I can get a Claims aware a identity for both an easy of additional data to the identoty and as a first step to eventually migrating to performing authentication via WIF (Windows Identity Foundation) with an STS (Security Token Service) service like ADFS (Active Directory Federation Services), but that's all later down the road.

My question is, what determines the timeout when a user is authenticated using SessionAuthenticationModule?

I used this page to get my authentication working, and it seems to work fine. Basically my authentication looks like this.

Snippet from my Login action method

var personId = securityService.AuthenticateUser(model.Login, model.Password);

if (!personId.IsEmpty())
{
    authenticationService.SignIn(personId, model.RememberMe);
    if (Url.IsLocalUrl(model.ReturnUrl))
        return Redirect(model.ReturnUrl);
    else
        return RedirectToAction("Index", "Home");
}

AuthenticationService.SignIn()

public void SignIn(Guid personId, bool createPersistentCookie)
{
    var login = securityService.GetLoginByPersonId(personId);
    if (String.IsNullOrEmpty(login.Name)) throw new ArgumentException("Value cannot be null or empty.", "userName");

    var claims = LoadClaimsForUser(login.Name);
    var identity = new ClaimsIdentity(claims, "Forms");
    var claimsPrincipal = new ClaimsPrincipal(identity);
    var token = new SessionSecurityToken(claimsPrincipal, ".CookieName", DateTime.UtcNow, DateTime.UtcNow.AddMinutes(30)) { IsPersistent = createPersistentCookie };
    var sam = FederatedAuthentication.SessionAuthenticationModule;
    sam.WriteSessionTokenToCookie(token);
}

AuthenticationService.LoadClaimsForUser()

private IEnumerable<Claim> LoadClaimsForUser(string userName)
{
    var person = securityService.GetPersonByLoginName(userName);
    if (person == null)
        return null;

    var claims = new List<Claim>();
    claims.Add(new Claim(ClaimTypes.NameIdentifier, person.PersonId.ToString()));
    claims.Add(new Claim(ClaimTypes.Name, userName));
    /* .... etc..... */
}

But there is the only concern I had with this is that I want to retain the behavior of sliding expiration so the user is not prompted to re-login when their login expires, but upon working on this problem I noticed that I can't find out what determines how long they stay logged in at all. I've set the session timeout, forms timeout and the validTo parameter on the SessionSecurityToken constructor to 1 minute, but even after that elapses, I'm still able to access the site. The cookie appears in the browser with an expiry date of "Session", which I'm not sure why but even if the cookie is valid for the session shouldn't the token, identity or whatever you want to call it expire after 1 minute and force the user to log back in?

Upvotes: 3

Views: 2988

Answers (1)

Wiktor Zychla
Wiktor Zychla

Reputation: 48250

I had similar issues once, here is my question containing my approach to invalidate cookies upon token expiration

How to set the timeout properly when federating with the ADFS 2.0

Adding a bit of different logic gives you sliding expiration

http://brockallen.com/2013/02/17/sliding-sessions-in-wif-with-the-session-authentication-module-sam-and-thinktecture-identitymodel/

web.config - Setting MaxClockSkew

<system.identityModel>
  <identityConfiguration>
    <securityTokenHandlers>
      <securityTokenHandlerConfiguration maximumClockSkew="0">
        </securityTokenHandlerConfiguration>
    </securityTokenHandlers>
  </identityConfiguration>
</system.identityModel>

Upvotes: 3

Related Questions