4

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?

Ian Griffiths
  • 14,302
  • 2
  • 64
  • 88

2 Answers2

6

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

Cœur
  • 37,241
  • 25
  • 195
  • 267
leastprivilege
  • 18,196
  • 1
  • 34
  • 50
  • Just to clarify, by "identity model" in this context, you mean the Thinktecture identity model library, not System.IdentityModel? (...which presumably means this isn't supported out of the box by Microsoft's identity framework?) – Ian Griffiths Feb 15 '13 at 22:10
  • 1
    Yes. It is Supported by MS, but Web API does not use it (since it is designed to work on 4.0 and 4.5). I just provided the glue in my library. – leastprivilege Feb 16 '13 at 07:10
  • @leastprivilege or Ian/Ruben - do any of you folks know if ASP.NET Identity 2.0 has integrated support for client certificate based authentication? If not can I integrate the `Thinktecture.IdentityModel` and use it just for client cert based auth and continue to use asp.net identity default auth + store for simple auth/external auth? I would be very interested in knowing if Ian was able to get a working solution, though I am on ASP.NET MVC 5 and Identity 2.0. – Sandeep Phadke May 29 '14 at 06:11
1

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.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • 1
    That sounds a whole lot more complicated. It means I'd need to either write or find a suitable external ID provider, and it would also force my clients to understand federated authentication, so it would complicate the implementation at both ends. And I'd have an extra service to maintain. Pushing the mapping elsewhere makes sense when you actually want to federate, but in this case I have no particular need for that, so there doesn't seem to be a payoff. (I'd still have to implement the cert handling and mapping, it's just moved to a different server.) – Ian Griffiths Feb 15 '13 at 22:47