February 5th, 2012

Claims Identity + C# 4.0 Dynamics

In this post I want to share with you something that I always use when I work with claim-based identity using Windows Identity Foundation.

As you probably know, when you use claim-based identity in a project using WIF you have access to the user claims in the System.Thread.CurrentPrincipal.Identity property, but there is an small problem, it’s type is System.Security.IIdentity and to access to the claims you need to cast that property to Microsoft.IdentityModel.Claims.IClaimsIdentity so you end up with something like this in the middle of your app:

((IClaimsIdentity)Thread.CurrentPrincipal.Identity).Claims

That’s not sexy at all, and it gets worse if you need an specific claim, for example the email address of the user:

var user = ((IClaimsIdentity)Thread.CurrentPrincipal.Identity);

var email = user.Claims.FirstOrDefault(x =>
    x.ClaimType.Equals(ClaimTypes.Email, StringComparison.OrdinalIgnoreCase))
    .Value;

You can solve this with a simple extension method something like GetClaimValue(string claimType), and you’ll get something like this, but is still not sexy:

var user = ((IClaimsIdentity)Thread.CurrentPrincipal.Identity); 

var email = user.GetClaimValue(ClaimTypes.Email);

Wouldn’t it be better to have something like this?

var email = user.Email;

Yes, you guessed, using C# 4.0 dynamics and a little of reflection, that’s possible, we simply need to create a class called DynamicIdentity that extends the DynamicObject class, and find in the ClaimTypes (or in any class we want) the value for the type requested using the property name to search. For example, if we write user.Email we are asking for all the  claims defined  with the claim type ClaimTypes.Email (“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress”).

This is how the DynamicIndentity class looks like:

public class DynamicIdentity : DynamicObject
{
    private ClaimTypeResolver claimTypeResolver;
    private IEnumerable<Claim> claims;

    public DynamicIdentity(IEnumerable<Claim> claims, ClaimTypeResolver typeResolver)
    {
        this.claims = claims;
        this.claimTypeResolver = typeResolver;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var claimType = this.claimTypeResolver.Resolve(binder.Name);

        var claims = this.claims.Where(x =>
            x.ClaimType.Equals(claimType, StringComparison.OrdinalIgnoreCase));

        if (claims.Count() == 0)
        {
            throw new ArgumentException(
                string.Format("Claim with type '{0}' was not found", claimType));
        }

        if (claims.Count() == 1)
        {
            result = claims.First().Value;
            return true;
        }

        result = claims.Select(x => x.Value).ToArray();
        return true;
    }
}

The ClaimTypeResolver class is responsible for resolving the Claim Type value based on the property name:

public class ClaimTypeResolver
{
    private Type[] typesDefinition;

    public ClaimTypeResolver(Type[] typesDefinition)
    {
        this.typesDefinition = typesDefinition;
    }

    public string Resolve(string friendlyName)
    {
        foreach (var type in this.typesDefinition)
        {
            var field = type.GetField(friendlyName);

            if (field != null)
            {
                return field.GetRawConstantValue().ToString();
            }
        }

        throw new ArgumentException(
            string.Format("Claim Type '{0}' was not found.", friendlyName));
    }
}

Notice that it receives an array with the types that contains the constants for your claim types.

Once we have that, we just need to create and extension method of the IPrincipal class that returns this dynamic object:

public static dynamic AsDynamic(this IPrincipal user)
{
    var claims = ((IClaimsIdentity)user.Identity).Claims.AsEnumerable();

    var resolver = new ClaimTypeResolver(new Type[]
    {
        typeof(ClaimTypes),
        typeof(MyCompanyClaimTypes),
    });

    return new DynamicIdentity(claims, resolver);
}

That’s all, this is the final experience for the developer:

var user = Thread.CurrentPrincipal.AsDynamic();

Console.WriteLine("Email: {0}", user.Email);

foreach (var role in user.Role)
{
    Console.WriteLine("Role: {0}", role);
}

Download the code here!

Leave a Reply