1
votes

I have problems with configuring my asp.net web api service to authenticate requests by client certificates

I do the steps describing in Pro ASP.NET Web Api Security:

  1. I create certificates using makecert.exe makecert.exe -r -n "CN=MobileTradeDataGateway" -pe -sv MobileTradeDataGateway.pvk -a sha256 -cy authority MobileTradeDataGateway.cer and makecert.exe -iv MobileTradeDataGateway.pvk -ic MobileTradeDataGateway.cer -n "CN=DataGateway1" -pe -sv DataGateway1.pvk -a sha256 -sky exchange DataGateway1.cer -eku 1.3.6.1.5.5.7.3.2
  2. I install MobileTradeDataGateway certificate in server Trusted Root Certification Authorities and in client too. Install DataGateway1 in client personal authority.
  3. Configure site to accept certificates and enable. Enable anonymous authentication.
  4. Create DelegatingHandler and add it to messagehandlers collection in mvc to check certificates.
  5. Call web api method

    var certStore = new X509Store(StoreLocation.CurrentUser); certStore.Open(OpenFlags.ReadOnly); var collection = certStore.Certificates.Find(X509FindType.FindByIssuerName, "MobileTradeDataGateway", true); var cert = collection[0]; certStore.Close(); var messageHandler = new WebRequestHandler(); messageHandler.ClientCertificates.Add(cert); var client = new HttpClient(messageHandler) { BaseAddress = new Uri("...") }; var res = client.GetAsync("/api/orderuploader?number=5").Result;

.

Everything works fine in my local machine and network where my machine is server. But when I deploy it to azure cloud service I get null var cert = request.GetClientCertificate(); // here is null in my custom delegating handler

Off course I enable IIS to accept certificates and correctelly put certificates in Trusted Root Certification Authorities

Any ideas?

3

3 Answers

0
votes

Did you also tried getting your certificate by "Thumbprint". here is a sample code that tries to read a certificate from certificate store.

private X509Certificate2 FindCertificate()
{
    X509Store certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    certificateStore.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = certificateStore.Certificates;
    X509Certificate2Collection matchingCertificates = certificates.Find(X509FindType.FindByThumbprint, "CertThumbprint", false);
    if (matchingCertificates != null && matchingCertificates.Count > 0)
    {
        return matchingCertificates[0];
    }
    throw new ArgumentException("Unable to find a matching certificate in the certificate store. Please modify the search criteria.");
}

this link has more information on how you can read certificate from a web /worker role

0
votes

Here is the code of my delegatinghandler from web api

public class X509ClientCertificateHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
        {
            WebApiEventSource.Log.InvalidHttpsScheme();
            return request.CreateResponse(HttpStatusCode.Forbidden);
        }
        var cert = request.GetClientCertificate(); // here is null!!!
        if (cert == null)
        {
            WebApiEventSource.Log.FailureAuthenticate("certificate is abcent", "", "");
            return request.CreateResponse(HttpStatusCode.Unauthorized);
        }
        var chain =new X509Chain {ChainPolicy = {RevocationMode = X509RevocationMode.NoCheck}};
        if (chain.Build(cert) && cert.Issuer.Equals("CN=MobileTradeDataGateway"))
        {
            var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, cert.Subject.Substring(3))
                };
            var principal = new ClaimsPrincipal(new[] {new ClaimsIdentity(claims, "X509")});
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
                HttpContext.Current.User = principal;
            WebApiEventSource.Log.SuccessAuthenticate(cert.SubjectName.Name);
            return await base.SendAsync(request, cancellationToken);
        }
        WebApiEventSource.Log.FailureAuthenticate("certificate is incorrect", cert.IssuerName.Name, cert.SubjectName.Name);
        return request.CreateResponse(HttpStatusCode.Unauthorized);
    }
}
0
votes

I think you have missed to upload the certificate to Azure Portal. Please make sure you upload .cer or .pfx certificate to Azure Portal. Let me know if you need help on how to upload etc.