Customizing IdentityServer

IdentityServer was designed with extensibility in mind. And since the question how to do that comes up quite frequently, here’s a overview to get you started.

Certain parts of IdSrv that we thought might need to be extended or customized are abstracted using interfaces – e.g. how to store and retrieve certificates or how to authenticate a user. You can find all the interface in the Core project’s Repositories folder.

Configuration data storage & retrieval

  • IConfigurationRepository (general and protocols configuration)
  • IClientCertificateRepository (X.509 client certificates and their mappings to user accounts)
  • IClientRepository (OAuth2 clients)
  • IDelegationRepository (WS-Trust identity delegation mappings)
  • IIdentityProviderRepository (WS* and OAuth2 identity providers)
  • IRelyingPartyRepository (relying parties and resources)

Runtime data access

  • ICodeTokenRepository (OAuth2 authorization codes and refresh token handling)
  • IClaimsRepository (claims retrieval for token generation)
  • IClaimsTransformationRulesRepository (claims transformation logic for external identity providers)
  • IUserManagementRepository (user management)
  • IUserRepository (user authentication)

All these extensibility points are wired up using MEF. MEF in turn reads from the repositories.config file in the WebSite project. So in other words, when you want to customize a certain part of IdSrv, implement the right interface and replace the default implementation with yours in repositories.config.

Most common scenario: customize authentication and claims retrieval
By far the most common task is to adapt IdSrv to an existing credential and attribute store. That’s actually quite easy to achieve.

The IUserRepository interface takes care of authentication:

public interface IUserRepository

{

    bool ValidateUser(string userName, string password);

    bool ValidateUser(X509Certificate2 clientCertificate, out string userName);

    IEnumerable<string> GetRoles(string userName);       

}

 

ValidateUser does either username/password or client certificate based authentication. You only need to implement what you want to support.
GetRoles return roles for IdSrv internal authorization, e.g. users (that can request tokens) have to be in the IdentityServerUsers role. Admins (that can administer IdSrv but can’t request tokens) have to be in the IdentityServerAdministrators role.

The IClaimsRepository interface abstracts claims generation and the corresponding metadata:

public interface IClaimsRepository
{
    IEnumerable<Claim> GetClaims(ClaimsPrincipal principal, 
RequestDetails
requestDetails);
    IEnumerable<string> GetSupportedClaimTypes();
}

 

GetClaims returns a list of claims for a given principal. The requestDetails parameter has information about the relying party/resource the token is for.
GetSupportClaimTypes is used to augment the WS-Federation metadata document with the supported claim types.

HTH

PS. Yes I am aware that these extensibility points are not really repositories. Historically they were named like this, and that’s now the way it is ;)

Posted in IdentityServer | Leave a comment

ASP.NET Web API Authentication: Using multiple (simultaneous) Authentication Methods with Thinktecture AuthenticationHandler

Since day one it was possible to support multiple authentication methods with AuthenticationHandler (see here, here and here for some background). I simply stopped searching for other credentials once I found one of the registered ones. Since one of my clients also needed a feature to support multiple simultaneous authentication methods, I finally found the time to add this feature.

AuthenticationHandler will now search for all registered credential mappings and add each resulting claims identity to a claims principal. This allows for scenarios where you want to support e.g. SSL client certificates in addition to Basic Authentication – or in delegation style scenarios where you need to transmit two sets of credentials – the direct caller as well as the original client credentials.

After all identities have been hydrated from the registered credentials, you can also optionally run a claims authentication manager to normalize the multiple identities into a unified single identity again.

The server configuration could e.g. look like this:

authentication.AddBasicAuthentication(UserCredentials.Validate);

authentication.AddClientCertificate(ClientCertificateMode.ChainValidation);

 

…and the corresponding client:

var handler = new WebRequestHandler();
handler.ClientCertificates.Add(
    X509.CurrentUser.My.SubjectDistinguishedName.Find("CN=Client").First());
 
var client = new HttpClient(handler) {
    BaseAddress = _baseAddress
};
 
client.SetBasicAuthentication("bob", "bob");

 

The resulting ClaimsPrincipal will then hold two identities, one containing claims for the Basic Authentication (name) and one containing claims for the client certificate (thumbprint, common name, serial number, public key, etc…)

The sample can be found here. Nuget will be updated soon.

HTH

Posted in IdentityModel, Uncategorized, WebAPI | Leave a comment

LeastPrivilege on Flipboard

Curated content seems to be the new thing, here’s mine:

http://flip.it/C9sav

Posted in Uncategorized | Leave a comment

Support for X.509 Client Certificates in Thinktecture.IdentityModel for Web API

Reblogged from www.leastprivilege.com:

Another RTM feature I was waiting for is (reasonable) SSL client certificate support in Web API.

Just like all the other authentication methods, you configure client certificate support on the AuthenticationConfiguration object. The following code configures the certificate to chain validation + check for a specific issuer subject name:

config.AddClientCertificate(

ClientCertificateMode.ChainValidationWithIssuerSubjectName,

"CN=TestCA");

Validation modes are:

  • Chain validation only
  • Peer validation…

Read more… 112 more words

An old post. But since I am writing about AuthenticationHandler..this is still relevant!
Posted in ASP.NET, IdentityModel, Uncategorized, WebAPI | 8 Comments

Web API Security: JSON Web Token/OAuth2 with Thinktecture.IdentityModel AuthenticationHandler

(OK – I only included OAuth2 in the title to get your attention – this applies to whatever framework or technology you use to work with JSON web tokens aka JWTs)

Following the pattern from my two previous posts, you can also validate JWTs with a simple extension method over the basic AddMapping functionality.

For validating a JWT you need to specify three items:

  • The name of the issuer that you expect the JWT to come from (an identity provider or authorization server)
  • The expected audience (a symbolic name of the service consuming the JWT)
  • The key material to validate the signature (either a symmetric key or a X.509 certificate)

The following method adds a mapping for an incoming Authorization header with a scheme of Bearer – the response will also contain the Bearer scheme. The key used is a symmetric key:

authentication.AddJsonWebToken(

    issuer: Constants.IdSrv.IssuerUri,

    audience: Constants.Audience,

    signingKey: Constants.IdSrv.SigningKey);

 

The current extension methods of IdentityModel uses my own JWT implementation – but in the sample (as well as in the latest IdentityServer version) I have already switched to Microsoft’s JWT handler. The signature of the extension methods stay the same.

Given the flexibility of the AuthenticationHandler, you can also fetch the JWT from other places like an alternative header or a query string. Another emerging pattern is to return the audience of the service and the URL of the token endpoint in the 401 response – again – easy to accomplish:

authentication.AddJsonWebToken(
    issuer: Constants.IdSrv.IssuerUri,
    audience: Constants.Audience,
    signingKey: Constants.IdSrv.SigningKey,
    options: AuthenticationOptions.ForAuthorizationHeader("Bearer"),
    scheme: AuthenticationScheme.SchemeAndChallenge(
        "urn:myapi", "url=https://idsrv.local/issue/token"));

 

HTH

Posted in .NET Security, IdentityModel, IdentityServer, OAuth, WebAPI | 1 Comment

Web API Security: Basic Authentication with Thinktecture.IdentityModel AuthenticationHandler

In my last post, I showed how to configure the AuthenticationHandler using the AddMapping method. While you have full control here, I added a number of convenience extension methods that cover common use case. Following is an overview of the HTTP Basic Authentication related extensions.

Simple
The following code is the simplest way to setup Basic Authentication:

  • Credential is expected on the Authorization header using a scheme of Basic
  • Validation is done by the default membership provider
  • Www-Authenticate header with scheme of Basic and a realm of localhost get sent back with the 401
var config = new AuthenticationConfiguration
{
    RequireSsl = true
};
            
// delegate validation to membership provider
config.AddBasicAuthentication(Membership.ValidateUser);

 

In addition you can pull roles from the default role provider like this (or any other method with the same signature):

// delegate validation to membership and fetch roles from role manager
config.AddBasicAuthentication(
    Membership.ValidateUser, 
    Roles.GetRolesForUser);

 

Custom credential validation
You can use whatever logic you like to validate the credentials. As long as your method takes two strings (user name and password) and returns a bool (success or not).

// custom username validator
config.AddBasicAuthentication(ValidateUser);

 

When credential validation fails, a 401 status code gets sent back. You can control the exact layout of the response by throwing an AuthenticationException inside the credential validation logic. The following code shows how to send back a 400 (bad request) instead of a 401 (sample code!):

private static bool ValidateUser(string userName, string password)
{
    if (userName == "bob")
    {
        throw new AuthenticationException
        {
            StatusCode = HttpStatusCode.BadRequest,
            ReasonPhrase = "Invalid client"
        };
    }
 
    return true;

}

Retain password
Sometimes you want to defer validation of credentials, or need the client password for delegation. In that case you can use the retain password option to save the password as a password claim that you can access later from the claims collection:

// retain password
config.AddBasicAuthentication(ValidateUser, retainPassword: true);
 

Custom realm and headers
You can also specify a realm for the response header:

// different realm

config.AddBasicAuthentication(ValidateUser, “MyRealm”);

…and to look for credentials on a different header:

// different header
config.AddBasicAuthentication(
    ValidateUser, 
    AuthenticationOptions.ForHeader("X-Authorization"), 

    “My Realm”);

 

Claims Transformation
If you need more control over the returned claims, you can specify a ClaimsAuthenticationManager derived implementation on AuthenticationConfiguration.

You can of course also create new extension methods over the raw AddMapping functionality if something you frequently need is missing.

HTH

Posted in IdentityModel, WebAPI | 26 Comments

ASP.NET Web API Security: The Thinktecture.IdentityModel AuthenticationHandler

AuthenticationHandler is an ASP.NET Web API message handler that can map incoming credentials to a token handler. The token handler in turn can parse credentials and create a principal.

In addition AuthenticationHandler provides some common services like claims transformation, session tokens and handling of response headers.

AuthenticationHandler

Your job is to do provide the mapping between credential and token handler, e.g.

  • Basic Authentication credentials on the Authorization header
  • JWT or SAML token on the Authorization header
  • Client certificate
  • Access key on the query string
  • Signature over incoming HTTP request

…and which authentication hint gets sent back (along the 401 status code).

For this definition you use the AuthenticationOptionMapping class:

var mapping = new AuthenticationOptionMapping

{

    // where to look for credentials

    Options = options,

               

    // how to validate them

    TokenHandler = handler,

               

    // which hint to give back if not successful

    Scheme = scheme

};

Options could be e.g.:

  • the Authorization header (with some scheme)
  • some other HTTP header
  • a query string parameter
  • a client certificate
  • a cookie

Thinktecture IdentityModel comes with several pre-defined token handlers, e.g.

  • JWT, SWT and SAML tokens
  • Basic Authentication
  • client certificates
  • access keys

…and last but not least, you have control over the Www-Authenticate header that get’s sent back if authorization was not successful, e.g.

  • some scheme and some realm
  • scheme only
  • scheme and some challenge

You can add all required associations to the authentication configuration:

var config = new AuthenticationConfiguration
{
    RequireSsl = true
};
 

config.AddMapping(mapping);

…and finally add the handler to the Web API runtime:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
 
var authConfig = ConfigureAuthentication();
config.MessageHandlers.Add(new AuthenticationHandler(authConfig));

 

After that, authentication handler will inspect every request, look for credentials, and if successful create and populate the principal.

HTH

Posted in IdentityModel, OAuth, WebAPI | 6 Comments