ASP NET Web API with Mutual TLS authentication on self hosted server

2.2k Views Asked by At

I'm trying to implement a client certification validation on a self-hosted web server. My first attempt was to check if the request contains a client certificate but I'm stuck here because Request.GetClientCertificate() always returns null.

This is my auth attribute class.

public class CustomAuthAttirbute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext actionContext)
    {
        X509Certificate2 cert = actionContext.Request.GetClientCertificate();
        if (cert == null)
        {
            actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
            {
                ReasonPhrase = "Client Certificate Required"
            };
        }
        else
        {
            // Validate the certificate
        }

        base.OnAuthorization(actionContext);
    }
}

I'm using Postman as REST client, with Postman I send client certitificate as documentated here Working with certificates. In the Postman console I can see that the certificate was sent successfully.

I created another server with nodejs following this tutorial to be sure that my certificates are ok and the Postman client are ok too. This server works fine and I can successfully authorize the Postman client.

So, I think the problem is related to C# self-hosted server only.

Unfortunately I can't use IIS or other web servers, I can only use a self-host setup like this or with OWIN Katana.

This is my current entry point and configuration:

class Program
{
    static void Main(string[] args)
    {
        var config = new MyHttpsSelfHostConfiguration("https://localhost:5005");

        config.Routes.MapHttpRoute(
            "API Default", "api/{controller}/{id}",
            new { id = RouteParameter.Optional });

        using (HttpSelfHostServer server = new HttpSelfHostServer(config))
        {
            server.OpenAsync().Wait();
            Console.WriteLine("Press Enter to quit.");
            Console.ReadLine();
        }
    }

    class MyHttpsSelfHostConfiguration : HttpSelfHostConfiguration
    {
        public MyHttpsSelfHostConfiguration(string baseAddress) : base(baseAddress) { }
        public MyHttpsSelfHostConfiguration(Uri baseAddress) : base(baseAddress) { }
        protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
        {
            httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
            httpBinding.Security.Mode = HttpBindingSecurityMode.Transport;
            return base.OnConfigureBinding(httpBinding);
        }
    }
}

These are some additional steps I took:

  • Bind the certificate to HTTPS. netsh http add sslcert ipport=0.0.0.0:5005 appid={ca7f9e45-f183-414f-8baf-b02d88310766} certhash=bd759f39dc966e0ef131cafde4ab273e9c2d5134 clientcertnegotiation=enable
  • Add a reservation entry for my URL. netsh http add urlacl url=https://localhost:5005/ user=Everyone
0

There are 0 best solutions below