简体   繁体   中英

Client Certificate Mapping Authentication in self-hosted Owin endpoint

Is it possible (and if so, how?) to configure a self hosted owin endpoint to use client certificate mapping authentication with A/D? IIS has this feature link , but so far I have not found an equivalent for self-hosted endpoints.

The way in which I have gotten this to work though (bearing in mind this approach is probably not 100% foolproof), is a 2-step process by using a combination of authenticationSchemeSelectorDelegate and OWIN.

This will choose the appropriate AuthenticationScheme (allowing requests containing a cert through, otherwise deferring to NTLM authentication)

public void Configuration(IAppBuilder appBuilder)
{
    var listener = (HttpListener)appBuilder.Properties[typeof(HttpListener).FullName];
    listener.AuthenticationSchemeSelectorDelegate += AuthenticationSchemeSelectorDelegate;
}

private AuthenticationSchemes AuthenticationSchemeSelectorDelegate(HttpListenerRequest httpRequest)
{
    if (!httpRequest.IsSecureConnection) return AuthenticationSchemes.Ntlm;
    var clientCert = httpRequest.GetClientCertificate();
    if (clientCert == null) return AuthenticationSchemes.Ntlm;
    else return AuthenticationSchemes.Anonymous;
}

This will read the contents of the cert and populate the "server.User" environment variable accordingly

public class CertificateAuthenticator
{
    readonly Func<IDictionary<string, object>, Task> _appFunc;

    public CertificateAuthenticator(Func<IDictionary<string, object>, Task> appFunc)
    {
        _appFunc = appFunc;
    }

    public Task Invoke(IDictionary<string, object> environment)
    {
        // Are we authenticated already (NTLM)
        var user = environment["server.User"] as IPrincipal;
        if (user != null && user.Identity.IsAuthenticated) return _appFunc.Invoke(environment);

        var context = environment["System.Net.HttpListenerContext"] as HttpListenerContext;
        if (context == null) return _appFunc.Invoke(environment);

        var clientCertificate = context.Request.GetClientCertificate();

        // Parse out username from certificate

        var identity = new GenericPrincipal
        (
            new GenericIdentity(username), new string[0]
        );

        environment["server.User"] = identity;
    }
}

Is there not a better/standardized way?

I have not seen any standard components built for this yet. That said, it should be possible to clean up your code a little:

  • You don't need to downcast to HttpListenerContext to get the client cert. The client cert should already be available in the OWIN environment under "ssl.ClientCertificate". See https://katanaproject.codeplex.com/wikipage?title=OWIN%20Keys . You'll also want to check ssl.ClientCertificateErrors because the cert may not have passed all validation checks.
  • You don't need the AuthenticationSchemeSelectorDelegate code. You could just set the listner.AuthenticationSchemes = NTLM | Anonymous. Then you add a middleware after your cert middleware that returns a 401 if server.User is not valid.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM