Ian Griffiths
Ian Griffiths

Reputation: 14567

Client Certificates and Claims-Based Identity in Web API

If a client accessing an endpoint implemented as an ASP.NET Web API Controller over HTTPS provides a client certificate, that certificate is available through Request.GetClientCertificate. However, I'm wondering: is it possible to get information provided in the form of claims-based model that was integrated with the security model in .NET 4.5?

The main reason I'd like to do this is that I need different clients to be able to authenticate in different ways to access the same services, so I'd prefer to abstract away from specifics such as certificates. I want my controller to be able to base its decisions on the claims for the current user without concerning itself about the provenance of those claims.

I know there's a X509CertificateClaimSet type, which makes it seem like the natural flow would be:

  1. Client certificate passed via TLS/SSL gets represented as an X509CertificateClaimSet through some sort of token mapping process (similar to how the incoming cookie generated by the federated provider you can use for ACS gets handled by the SessionSecurityTokenHandler
  2. A claims transformation module (something derived from ClaimsAuthenticationManager and configured with a <claimsAuthenticationManager> element) inspects the claim set that came from the certificate, and transforms that into non-token-specific application-specific claims
  3. The handler looks for the application-specific claims.

There's even a X509SecurityTokenHandler, which sounds like it should do this. However, as far as I can tell, that's designed for scenarios where the certificate-based authentication is handled within the messages being sent - it doesn't appear to have any support for the scenario where the proof of ownership of the certificate happened at the transport level, i.e. as part of the TLS/SSL handshake.

I'm wondering whether I need to write my own module to do this. In theory, it looks like it might be a case of just handling the AuthenticateRequest event, looking in the request for the certificate, constructing a X509CertificateClaimSet from the certificate if it's present. But...then what? Do I just create my own ClaimsPrincipal and replace the existing user? Or is there some 'correct' way to add the claims I've discovered to the set? (A client certificate is not necessarily the only source of claims - my application is already using claims that come from integration with ACS. Is there a standard mechanism for ensuring that all possible sources of claims are correctly merged?)

It looks likethe SessionAuthenticationModule (SAM) is the identity model component that currently provides a claims principal, and it just replaces the one that was previously in the context and also the current thread's user. But it appears to provide extensibility - if you override its ValidateSessionToken, that returns the set of ClaimsIdentity objects that make up the principal. So in theory, I could override that and add any additional claims at that point.

But I'm not sure that's the way to go. As far as I can tell, the SAM does this after the ClaimsAuthenticationManager has done its claims transformation. Or is claims transformation the wrong model to go with here?

Upvotes: 4

Views: 3311

Answers (2)

leastprivilege
leastprivilege

Reputation: 18502

Have a look here: client cert auth and claims generation is part of Thinktecture.IndetityModel.

Upvotes: 6

Wiktor Zychla
Wiktor Zychla

Reputation: 48314

If I were you, I would externalize the authentication - let some other services provide the authentication and just return SAML tokens with required claims.

This way, in your application you don't really think of certificates, you just expect some concrete claims from federated identity providers.

Then, you implement one of your identity providers to actually accept certificates but the outgoing SAML hides this implementation detail and translates the certificate to a claim set useful to your application.

Upvotes: 1

Related Questions