ASP.NET WebAPI Security 3: Extensible Authentication Framework

Posted by Your DisplayName here! on Least Privilege See other posts from Least Privilege or by Your DisplayName here!
Published on Tue, 13 Mar 2012 15:18:33 GMT Indexed on 2012/03/18 18:20 UTC
Read the original article Hit count: 357

Filed under:

In my last post, I described the identity architecture of ASP.NET Web API. The short version was, that Web API (beta 1) does not really have an authentication system on its own, but inherits the client security context from its host. This is fine in many situations (e.g. AJAX style callbacks with an already established logon session). But there are many cases where you don’t use the containing web application for authentication, but need to do it yourself. Examples of that would be token based authentication and clients that don’t run in the context of the web application (e.g. desktop clients / mobile).

Since Web API provides a nice extensibility model, it is easy to implement whatever security framework you want on top of it. My design goals were:

  • Easy to use.
  • Extensible.
  • Claims-based.

..and of course, this should always behave the same, regardless of the hosting environment. In the rest of the post I am outlining some of the bits and pieces, So you know what you are dealing with, in case you want to try the code.

At the very heart…
is a so called message handler. This is a Web API extensibility point that gets to see (and modify if needed) all incoming and outgoing requests. Handlers run after the conversion from host to Web API, which means that handler code deals with HttpRequestMessage and HttpResponseMessage. See Pedro’s post for more information on the processing pipeline.

This handler requires a configuration object for initialization. Currently this is very simple, it contains:

  • Settings for the various authentication and credential types
  • Settings for claims transformation
  • Ability to block identity inheritance from host

The most important part here is the credential type support, but I will come back to that later.

The logic of the message handler is simple:

  1. Look at the incoming request.
  2. If the request contains an authorization header, try to authenticate the client.
    1. If this is successful, create a claims principal and populate the usual places.
    2. If not, return a 401 status code and set the Www-Authenticate header.
  3. Look at outgoing response, if the status code is 401, set the Www-Authenticate header.

Credential type support
Under the covers I use the WIF security token handler infrastructure to validate credentials and to turn security tokens into claims. The idea is simple: an authorization header consists of two pieces: the schema and the actual “token”. My configuration object allows to associate a security token handler with a scheme. This way you only need to implement support for a specific credential type, and map that to the incoming scheme value. The current version supports HTTP Basic Authentication as well as SAML and SWT tokens.

(I needed to do some surgery on the standard security token handlers, since WIF does not directly support string-ified tokens. The next version of .NET will fix that, and the code should become simpler then).

You can e.g. use this code to hook up a username/password handler to the Basic scheme (the default scheme name for Basic Authentication).

config.Handler.AddBasicAuthenticationHandler(
(username, password) => username == password);

You simply have to provide a password validation function which could of course point back to your existing password library or e.g. membership.

The following code maps a token handler for Simple Web Tokens (SWT) to the Bearer scheme (the currently favoured scheme name for OAuth2). You simply have to specify the issuer name, realm and shared signature key:

config.Handler.AddSimpleWebTokenHandler(
   
"Bearer"
,
   
http://identity.thinktecture.com/trust
,
   
Constants
.Realm,
   
"Dc9Mpi3jaaaUpBQpa/4R7XtUsa3D/ALSjTVvK8IUZbg=");

For certain integration scenarios it is very useful if your Web API can consume SAML tokens. This is also easily accomplishable. The following code uses the standard WIF API to configure the usual SAMLisms like issuer, audience, service certificate and certificate validation. Both SAML 1.1 and 2.0 are supported.

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(Constants
.Realm));
adfsConfig.IssuerNameRegistry = registry;
adfsConfig.CertificateValidator =
X509CertificateValidator
.None;

// token decryption (read from configuration section)
adfsConfig.ServiceTokenResolver =
FederatedAuthentication
.ServiceConfiguration.CreateAggregateTokenResolver();

config.Handler.AddSaml11SecurityTokenHandler(
"SAML", adfsConfig);

Claims Transformation
After successful authentication, if configured, the standard WIF ClaimsAuthenticationManager is called to run claims transformation and validation logic. This stage is used to transform the “technical” claims from the security token into application claims. You can either have a separate transformation logic, or share on e.g. with the containing web application. That’s just a matter of configuration.

Adding the authentication handler to a Web API application
In the spirit of Web API this is done in code, e.g. global.asax for web hosting:

protected void Application_Start()
{
   
AreaRegistration
.RegisterAllAreas();

    ConfigureApis(
GlobalConfiguration
.Configuration);
    RegisterGlobalFilters(
GlobalFilters
.Filters);
    RegisterRoutes(
RouteTable
.Routes);

   
BundleTable.Bundles.RegisterTemplateBundles();
}
private void ConfigureApis(HttpConfiguration configuration)
{
    configuration.MessageHandlers.Add(
new AuthenticationHandler
(ConfigureAuthentication()));
}
private AuthenticationConfiguration ConfigureAuthentication()
{
   
var config = new AuthenticationConfiguration
    {
       
// sample claims transformation for consultants sample, comment out to see raw claims
        ClaimsAuthenticationManager = new ApiClaimsTransformer
(),

       
// value of the www-authenticate header,
// if not set, the first scheme added to the handler collection is used
        DefaultAuthenticationScheme = "Basic"
    };


   
// add token handlers - see above

    return config;
}

You can find the full source code and some samples here.

In the next post I will describe some of the samples in the download, and then move on to authorization.

HTH

© Least Privilege or respective owner