This post shows some of the implementation techniques for adding token and claims based security to HTTP/REST services written with WCF. For the theoretical background, see my previous post.
The framework I am using/building here is not the only possible approach to tackle the problem. Based on customer feedback and requirements the code has gone through several iterations to a point where we think it is ready to handle most of the situations.
Goals and requirements
- The framework should be able to handle typical scenarios like username/password based authentication, as well as token based authentication
- The framework should allow adding new supported token types
- Should work with WCF web programming model either self-host or IIS hosted
- Service code can rely on an IClaimsPrincipal on Thread.CurrentPrincipal that describes the client using claims-based identity
In WCF the main extensibility point for this kind of security work is the ServiceAuthorizationManager. It gets invoked early enough in the pipeline, has access to the HTTP protocol details of the incoming request and can set Thread.CurrentPrincipal. The job of the SAM is simple:
- Check the Authorization header of the incoming HTTP request
- Check if a “registered” token (more on that later) is present
- If yes, validate the token using a security token handler, create the claims principal (including claims transformation) and set Thread.CurrentPrincipal
- If no, set an anonymous principal on Thread.CurrentPrincipal. By default, anonymous principals are denied access – so the request ends here with a 401 (more on that later).
To wire up the custom authorization manager you need a custom service host – which in turn needs a custom service host factory. The full object model looks like this:
A nice piece of existing WIF infrastructure are security token handlers. Their job is to serialize a received security token into a CLR representation, validate the token and turn the token into claims.
The way this works with WS-Security based services is that WIF passes the name/namespace of the incoming token to WIF’s security token handler collection. This in turn finds out which token handler can deal with the token and returns the right instances.
For HTTP based services we can do something very similar. The scheme on the Authorization header gives the service a hint how to deal with an incoming token. So the only missing link is a way to associate a token handler (or multiple token handlers) with a scheme and we are (almost) done.
WIF already includes token handler for a variety of tokens like username/password or SAML 1.1/2.0. The accompanying sample has a implementation for a Simple Web Token (SWT) token handler, and as soon as JSON Web Token are ready, simply adding a corresponding token handler will add support for this token type, too.
All supported schemes/token types are organized in a WebSecurityTokenHandlerCollectionManager and passed into the host factory/host/authorization manager.
Adding support for basic authentication against a membership provider would e.g. look like this (in global.asax):
var manager = new WebSecurityTokenHandlerCollectionManager();
manager.AddBasicAuthenticationHandler((username, password) =>
Adding support for Simple Web Tokens with a scheme of Bearer (the current OAuth2 scheme) requires passing in a issuer, audience and signature verification key:
In some situations, SAML token may be used as well. The following configures SAML support for a token coming from ADFS2:
var registry = new ConfigurationBasedIssuerNameRegistry();
“d1 c5 b1 25 97 d0 36 94 65 1c e2 64 fe 48 06 01 35 f7 bd db”, “ADFS”); var adfsConfig = new SecurityTokenHandlerConfiguration();
adfsConfig.IssuerNameRegistry = registry;
adfsConfig.CertificateValidator = X509CertificateValidator.None; // token decryption (read from config) adfsConfig.ServiceTokenResolver =
The custom authorization manager will also try to invoke a configured claims authentication manager. This means that the standard WIF claims transformation logic can be used here as well. And even better, can be also shared with e.g. a “surrounding” web application.
A WCF error handler takes care of turning “access denied” faults into 401 status codes and a message inspector adds the registered authentication schemes to the outgoing WWW-Authenticate header when a 401 occurs.
The next post will conclude with authorization as well as the source code download.
(Wanna learn more about federation, WIF, claims, tokens etc.? Click here.)