Token based Authentication for WCF HTTP/REST Services: Authentication

Posted by Your DisplayName here! on Least Privilege See other posts from Least Privilege or by Your DisplayName here!
Published on Tue, 15 Nov 2011 16:04:12 GMT Indexed on 2011/11/15 18:06 UTC
Read the original article Hit count: 440

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.

Disclaimer
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

Implementation overview
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:

  1. Check the Authorization header of the incoming HTTP request
  2. Check if a “registered” token (more on that later) is present
  3. If yes, validate the token using a security token handler, create the claims principal (including claims transformation) and set Thread.CurrentPrincipal
  4. 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:

Token handling
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) =>
Membership.ValidateUser(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:

manager.AddSimpleWebTokenHandler(
   
"Bearer"
,
   
"http://identityserver.thinktecture.com/trust/initial"
,
   
"https://roadie/webservicesecurity/rest/"
,
   
"WFD7i8XRHsrUPEdwSisdHoHy08W3lM16Bk6SCT8ht6A=");

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();
registry.AddTrustedIssuer(
"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.AudienceRestriction.AllowedAudienceUris.Add(
new Uri("https://roadie/webservicesecurity/rest/"
));
adfsConfig.IssuerNameRegistry = registry;
adfsConfig.CertificateValidator =
X509CertificateValidator
.None; // token decryption (read from config) adfsConfig.ServiceTokenResolver =
IdentityModelConfiguration
.ServiceConfiguration.CreateAggregateTokenResolver();            
manager.AddSaml11SecurityTokenHandler(
"SAML", adfsConfig);

 

Transformation
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.

Error handling
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.)

© Least Privilege or respective owner

Related posts about IdentityModel

Related posts about IdentityServer