Use ClaimsAuthenticationManager To Make Sense Of Federated Identites

OK, so you figured you don’t want the burden of managing your users’ identities anymore. You can very well live without the responsibility of keeping their credentials save, and you have chosen to let the smart boys and girls that manage LiveID handle all that for you; you’re just using some STS (for example: Azure ACS) to let your users login with their LiveID. Good for you! Identity Federation is the way of the future, so why not start using it right now?

It does present you with a challenge, though, that you didn’t have in the olden days (not in its current form, at least). Suddenly, your user has an identity that, out-of-the-box, doesn’t mean all that much to your application. Let’s take the case of a simple webshop. If you enable users to get in using their LiveID, how are you gonna trace whether they are new or recurring customers? Did they already register a shippng address, payment details, and that sort of stuff? Back in the days of Forms Authentication, this info was usually gathered when the user registered himself with the application; now it’s a separate step that a logged in user may or may not have taken already.

So, the problem is clear: how do I keep track of users whose identities are external to my application? Of course there are more than one pieces to this puzzel: I have to worry about gathering the additional application-specific information, and I have to store some token to associate identities with this extra information. And then there is the issue of deciding whether a user that has just logged in is a new or a recurring user. This post presents a possible solution to this last problem, and shows how the WIF framework let’s you handle this quite nicely.

First off, let’s reformulate the problem in a more ‘claimsy’ type of language. In claims-world, everything there is to know about an identity is expressed in claims. For example: what we used to call a ‘role’ is now a claim of type ‘role’. An email address is now a claim of type ’emailaddress’. So we might say that being a properly registered customer for our webshop (where ‘properly registered’ means: having provided the application with your shipping details and having received a customerId in return), means to have a claim of type ‘customerId’. So now we can distinguish between logged in users of our webshop: those that have a claim ‘customerId’ are all set; those that don’t still need to register some details before they can place an order.

The problem now is: how do we set this extra claim at runtime if a recurring user logs in? As said, WIF has an extensibility point that let’s you handle these types of scenario’s. First of all, this requires you to provide your implementation of the ClaimsAuthenticationManager-class. This basically involves implementing the Authenticate-method as follows:

        [SecuritySafeCritical]
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (incomingPrincipal.Identity != null && incomingPrincipal.Identity.IsAuthenticated)
            {
                var identity = incomingPrincipal.Identity as ClaimsIdentity;
                int? customerId = null;
                // TODO: add logic that evaluates the incoming principal and retrieves customerId if available
                if (customerId != null)
                {
                    identity.AddClaim(new Claim(ClaimTypes.UserData, customer.Id.ToString()));
                }
            }

            return base.Authenticate(resourceName, incomingPrincipal);
        }

As a sidenote: notice the SecuritySafeCritical attribute above this method? That’s required because the method AddClaim() on ClaimsIdentity is marked as SecurityCritical so that SecurityTransparent code cannot call into it. (I actually feel that CAS may be dying a silent death these days, for several reasons, but that’s another discussion.)

So, now you’ve created your own ClaimsAuthenticationManager. All that’s left to do now is letting your app know that you want to use it. That’s done through the web.config:

  <system.identityModel>
    <identityConfiguration>
      <!-- All sorts of config stuff -->
      <claimsAuthenticationManager type="[Your fully qualified type]" />
    </identityConfiguration>
  </system.identityModel>

Now, your custom ClaimsAuthenticationManager is called when a user is authenticated against the STS of your choice and returns to your application with a token. You can now handle the login event and add application-specific claims to the incoming identity. Of course, these claims can also come from an external attribute store or whatever source you can think of.

One final note: if you are going to stuff loads and loads of claims in here, it may be a good idea to store the actual claims data of the server instead of in a cookie that travels to the client; some browsers may take issue with the fact that you feel storing an image blob in a cookie is appropriate :). To do that, you have to edit the global.asax and handle the Application_Start event. Paste the following code in there:

            FederatedAuthentication.FederationConfigurationCreated += (s, args) =>
            {
                FederatedAuthentication.SessionAuthenticationModule.IsReferenceMode = true;
            };

What this does is tell the SessionAuthenticationModule to store the actual claims data in the session, and pass the reference to that session object to the client through a cookie. Note that this requires either a single server deployment, or a form of session management where sessions are shared between servers.

OK, happing federating everyone! Please leave a comment if you have any follow-up questions.

Advertisements

2 thoughts on “Use ClaimsAuthenticationManager To Make Sense Of Federated Identites

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s