Tuesday, November 06, 2007

WCF: Caching Claims using System.Web.Caching

We use a custom legacy STS (Security Token Service) that assigns a ticket to our consumer applications, that they again pass as to our WCF services for authentication. The passed SAML token contains only the ticket, so we must then use the validated ticket to generate the System.IdentityModel claims used for authorization.

As the services are stateless, each WCF operation must recreate the AuthorizationContext and thus generate the claim sets again. When you compose a set of services into a business process, the claim sets will get generated over and over again. To avoid this, and get better performance, I needed to cache the claim sets by STS ticket for a limited time.

Many might not know this, but the System.Web.Caching.Cache can be used even in systems that are not an ASP.NET application or even hosted by IIS/ASP.NET. You will still get all the goodies, such as cache expiration, dependencies, throwing stuff out of the cache in case of low memory, etc.

We now cache the claim sets in a singleton using a generic <T> getter and setter with ticket-based keys like this:

public static class EApprovalCache
{
private static System.Web.Caching.Cache _cache = HttpRuntime.Cache;

public static Cache Cache
{
get { return _cache; }
}

public static object Add<T>(string ticket, T value)
{
string key = typeof(T).Name +":" + ticket;
return _cache.Add(key, value, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}

public static T Get<T>(string ticket)
{
string key = typeof(T).Name +":" + ticket;
return (T)_cache[key];
}
}

The claim set is retrieved and added to the cache like this:

_authorizationContext = EApprovalCache.Get<EApprovalAuthorizationContext> (context.Ticket);
if (_authorizationContext == null)
{
_authorizationContext = new EApprovalAuthorizationContext(session);
EApprovalCache.Add<EApprovalAuthorizationContext> (context.Ticket, _authorizationContext);
}

The claims are cached for max one hour; but if the user logs out and in again, then the user will have gotten another ticket and the claim set would be generated from scratch and not read from the cache.

1 comment:

Anonymous said...

This is a nice pattern.
I liked this better than the Microsoft Cache pattern, because of its low foot print.

Thank you.