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