I use client certificate authentication in ASP.NET Web API 2. I attach the certificate to the client as follows:
private HttpClient GetHttpClient()
{
HttpClient client = new HttpClient(GetRequestHandler());
client.BaseAddress = new Uri(_apiBaseUrl);
return client;
}
private WebRequestHandler GetRequestHandler()
{
WebRequestHandler wrh = new WebRequestHandler();
X509Certificate cert = GetClientCert();
wrh.ClientCertificates.Add(cert);
return wrh;
}
private X509Certificate GetClientCert()
{
X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate cert = certStore.Certificates.Find(X509FindType.FindBySubjectName, _certName, false)[0];
certStore.Close();
return cert;
}
When I debug this, I see that the cert object is what I expected. In the web API on the server, I use this:
public class CertAuthHandler : DelegatingHandler
{
private ICertValidator _certValidator;
public CertAuthHandler(ICertValidator certValidator)
{
this._certValidator = certValidator;
}
public CertAuthHandler() : this(new LoggingCertValidator()) { }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var cert = request.GetClientCertificate();
if (_certValidator.IsValid(cert))
{
return base.SendAsync(request, cancellationToken);
}
return Task<HttpResponseMessage>.Factory.StartNew(() => request.CreateResponse(HttpStatusCode.Unauthorized));
}
}
This works exactly as expected on our TEST server; however, on our DEV server, the record I added for troubleshooting shows that it request.GetClientCertificate()returns null. I double and triple checked that IIS is configured to accept client certificates; when I change it to an ssl request and require client certificates, it returns 403. If that matters, the web API is configured as a sub-application of the main website in both DEV and TEST.
, , , - , ( DEV TEST); 401. DEV API , , , , . , DEV, ? , , API. .