6
votes

I am using the excellent Thinktecture.IdentityModel library for performing authentication/authorization in an ASP.NET Web API project which will be consumed from mobile devices and possibly web clients. I am using basic authentication to authenticate mobile clients to access the web api, and utilizing the built in SessionToken generation that the Thinktecture.IdentityModel presents. However I have some concerns as to how to revoke claims added to a ClaimsIdentity claims collection, which are then (I think) encoded into the SessionToken provided to a client...

Here is what I have so far:

Following the examples in the IdentityModel sample project, I have created the following class

public static class  SecurityConfig
{
  public static void ConfigureGlobal(HttpConfiguration globalConfig)
  {
      globalConfig.MessageHandlers.Add(new AuthenticationHandler(CreateConfiguration()));
  }

  public static AuthenticationConfiguration CreateConfiguration()
  {
      var authentication = new AuthenticationConfiguration()
          {
              ClaimsAuthenticationManager = new MyClaimsTransformer(),
              RequireSsl = false, //TODO:TESTING only
              EnableSessionToken = true,
              SessionToken = new SessionTokenConfiguration()
              {
                  EndpointAddress = "/Authenticate"
              }
          };
       authentication.AddBasicAuthentication(Membership.ValidateUser);

      return authentication;
   }
}

Which is called from my Global.asax class like so

SecurityConfig.ConfigureGlobal(GlobalConfiguration.Configuration);

The mobile devices collects the username and password from an individual, and set the authentication header properly and supplies the credentials to the necessary web endpoint http://myhost/api/Authenticate

On the server, my Membership.ValidatUser is called with the username/password, and if validated, the Authenticate method of MyClaimsTransformer is called.

public class ClaimsTransformer : ClaimsAuthenticationManager
{
   public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
   {
     if (!incomingPrincipal.Identity.IsAuthenticated)
     {
        return base.Authenticate(resourceName, incomingPrincipal);
     }
     return incomingPrincipal;
   }
}

The mobile client then receives back a token, which it can pass along in the authentication header of any subsequent requests.

This all works great.

Now what I would like to do, is in the ClaimsTransformer, add some code that would do something like the following pseudocode.

var nameClaim = incomingPrincipal.Claims.First(c => c.Type == ClaimTypes.Name);

//Using value in nameClaim lookup roles or permissions for this user.
var someListofRoles = SomeMethodToGetRoles(nameClaim.Value);

//Add user roles to the Claims collection of the ClaimsPrincipal.
foreach(var role in someListOfRoles)
{
   incomingPrincipal.Identities.First().AddClaim(new Claim("Role", role.Name));
}

My hope was to limit the number of times I need to request the list of roles or permissions for a given user from the database, as well as make it convenient for checking these roles/permissions in a custom AuthorizeAttribute.

However as I started adding this, I began to think of scenarios where a user would have been logged in and would have received this token, but through some action by a different user of the system would have had their roles changed or revoked. The initial user would still have this token with a list of now expired roles/permissions and would have access to whatever until the token expired, or would have been given new access to something but would not actually receive that access until they somehow logout.

Is there a mechanism for invalidating a SessionToken created in this way? Or, if I found some way to know a change has been made to a users roles/permissions, how would I modify the claims and reissue a SessionToken in a seamless fashion?

Also, how does one just entirely revoke a SessionToken, ie if I wanted to 'logout' a user, how would that work?

2

2 Answers

4
votes

The session token facility does not have that feature. We wanted to keep it simple to get around the "type in password on every application start" problem. Revocation is hard to achieve without a complete data storage backend (that would work in web farms etc..).

You shouldn't store data that might change over session time in the session token.

0
votes

the database changes notification design is really upto you. what i suggest is like using timestamp/rowversion to check whether the data(user/role) is outdated. you may store this data timestamp/rowversion on server like user-session, or cookie/header at your client side. i recommend the former approach.

if outdated, i suggest you can just re-execute your CreateConfiguration() method, which should recreate all the necessary info reflecting the latest data changes related to the token.