Identifying AppFabric Access Control Service users uniquely

In my last posting about AppFabric Labs Access Control Service I described how to get your ASP.NET MVC application to work with ACS. In this posting I will dig deeper into tokens and claims and provide you with some helper methods that you may find useful when authenticating users using AppFabric ACS. Also I will explain you little dirty secret of Windows Live ID.

What is inside token?

TokenLet’s start with dissecting tokens. Token is like envelope that contains claims. Each claim carries some property of identity. By default we get the following claims from all identity providers:

  • name identifier – unique identifier for user that can be used to identify user (user can change his or her name in identity provider service but name identifier does not change),
  • identity provider – unique string that helps us detect identity provider that user used to authenticate to our web page.

As you can see from the image on right then token may contain more claims like claim for name and e-mail address. There can be also other claims if identity provider is able to provide them.

How claims are specified?

Claims are specified in web.config file when we add federation metadata definition to application using STS reference wizard. In my web.config there are following claims defined.

  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
  • http://schemas.microsoft.com/ws/2008/06/identity/claims/role
  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
  • http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider

You can find claims from microsoft.identitymodel block in web.config file.

Why Live ID gives us empty name?

This is the question that I had when I added ACS support to my ASP.NET MVC web application and here is the answer. Live ID returns for user only the name identifier and it does not introduce it as user name to Windows Identity Foundation. As there is no name claim then user name is left empty and you find weird situation where user is authenticated but there is no username.

When user is authenticated over Live ID we get back these claims:

  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
  • http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider

The values are something like this:

  • nameidentifier – QwxVt0jBnEUFw7B2HgfsaWeSQXIzAXC9yUKWR780UepE=
  • identityprovider – uri:WindowsLiveID

As you can see there is no claim for user name and that’s why user name is empty.

What Google returns?

Here is what Google returns when I authenticate myself:

  • nameidentifier – https://www.google.com/accounts/o8/id?id=AItOawlMC8j0cW8013mWBkEwXs6MsV5ixZUmxks
  • emailaddress – mygoogleusername@gmail.com
  • name – Gunnar Peipman
  • identityprovider – Google

Google asks user if he or she allows ACS to access my name and e-mail address. If I agree then my name and address are given to my web application and I have username filled correctly when asking for current user.

What data we should save for users?

This is the good question to ask because some services allow users to change their name. And names are not unique. Consider the name John Smith. There are hundreds of guys who have this name. There maybe also hundreds of Mary Smiths and as some of them get married they change their last name (if they don’t marry some John Smith, of course).

To be maximally fool-proof we have to save the values of identityprovider and nameidentifier claims to our users database. This way we can avoid the situation where two different identity providers give us same nameidentifier for different users.

Here is my claims extension class you can use to get the values of these fields easily.

public static class IdentityExtensions
{
   
public static string GetIdentityProvider(this IIdentity
identity)
    {
       
var claimsIndentity = identity as ClaimsIdentity
;
       
if (claimsIndentity == null
)
           
return string
.Empty;
 
       
var providerQuery = from c in
claimsIndentity.Claims
                           
where c.ClaimType == "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider"
                            select
c.Value;
       
var
provider = providerQuery.FirstOrDefault();
       
return
provider;
    }
 
   
public static string GetNameIdentifier(this IIdentity
identity)
    {
       
var claimsIndentity = identity as ClaimsIdentity
;
       
if (claimsIndentity == null
)
           
return string
.Empty;
 
       
var providerQuery = from c in
claimsIndentity.Claims
                           
where c.ClaimType == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
                            select
c.Value;
       
var
provider = providerQuery.FirstOrDefault();
       
return provider;
    }
}

And here is how we can use these extension methods.

var identity = User.Identity;
var provider = identity.GetIdentityProvider();
var nameId = identity.GetNameIdentifier();

What about names?

As some providers doesn’t support returning names we have two options:

  • avoid these providers (like I currently do),
  • ask new users for (unique) username or first and last name when they are joining.

Right now I am trying to work out solution for second option so I have easy way how to handle separate user names support easily so I don’t have to write tons of code for this simple thing.

Conclusion

Claims based authentication is powerful way to identify users and AppFabric ACS lets our sites to support different identity providers so we don’t have to write code for each one of them. As identity providers support different features and does not return us always all the data we would like to have we have to be ready to handle the situation (like Windows Live ID). As we saw it was still easy to identify users uniquely because data for this purpose is always given to us with token.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    Leave a Reply

    Your email address will not be published. Required fields are marked *