Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
800 views
in Technique[技术] by (71.8m points)

c# - HttpRequestMessage.GetClientCertificate() returns null in Web API

I have a .NET4.5 WebAPI 2 app that uses SSL Client Certificates for some custom security related checks.

When debugging the app, request.GetClientCertificate() returns null for any service call, no matter what I tried so far.

The Tested Code:

Basically, on my service's side, I have a method that goes something like this:

class CertificateChecker : ICertificateChecker
{
    public bool Check(HttpRequestMessage request)
    {
        var cert = request.GetClientCertificate();
    }
}

My unit tests with the client cert attached to the request using request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, cert) pass (the cert comes out exactly as expected, validations work, and so on).

However, when I use a test with an HttpClient calling the actual WebAPI app, with the break point set at the request.GetClientCertificate() line on service side, the same line returns null.

Here's what I tried:

Client Certs:

  • Created a fake CA and put it into trusted CA store (tried both LocalMachine and current user).
  • Created a Client Authentication (1.3.6.1.5.5.7.3.2) cert signed by that Fake CA and placed it into the Personal store (LocalMachine and Current User).

(basically, followed https://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/ and similar blogs)

On my test that calls the service using HttpClient, attached the client cert in the following ways (none of which worked):

  • Using WebRequestHandler with ClientCertificateOptions set to Manual and the cert added to the ClientCertificates collection.

    using (var handler = new WebRequestHandler())
    {
         var cert = GetTestCert();
         handler.ClientCertificateOptions = ClientCertificateOption.Manual;
         handler.ClientCertificates.Add(cert);
    
         // and so on...
    }
    
  • Using the HttpRequestMessage, adding the cert as a property with the key set to HttpPropertyKeys.ClientCertificateKey (this approach works when unit testing as described above).

    request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, cert);
    

The cert variable is set to the expected X509Certificate2 object in both cases.

Hosting:

  • IISExpress: Tried to run the app in IISExpress.

    Edited applicationhost.config with iisClientCertificateMappingAuthentication enabled set to "true" and the following access settings (neither worked):

    <access sslFlags="Ssl, SslNegotiateCert" />
    <access sslFlags="SslNegotiateCert" />
    
  • Local IIS Set the web app to run in IIS on my local machine

    • The site in IIS is configured with an HTTPS binding using a trusted certificate.
    • Web app configured to use https protocol with IIS Client Cert mapping authentication enabled.
    • Tried both the access option combinations (Ssl, SslNegotiateCert and SslNegotiateCert) (via configuration editor)

In both cases, when accessing the web api via the https url using a web browser, I get the index view of the home controller to show without issue (so, the server side cert is trusted).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I know it is a bit old but I was facing the same issue and i solved it by followinfgthis article:

https://improveandrepeat.com/2017/07/how-to-configure-iis-express-to-accept-ssl-client-certificates/

The problem was a configuration on the IIS server, which can be modified also on IIS express. I report it in case the link will not be available.

For IIS change the server configuration file, for IIS Express modify the file under your solution located in .vsconfigapplicationhost.config

Search for an xml element called inside a element:

<security>
  <access sslFlags="None" />

The default configuration has no support for SSL client certificates. You need to modify the sslFlags attribute to include these options: Ssl, SslNegotiateCert, SslRequireCert

<security>
        <access sslFlags="Ssl, SslNegotiateCert, SslRequireCert" />

The next step is to find the element :

<iisClientCertificateMappingAuthentication enabled="false"></iisClientCertificateMappingAuthentication>

If you change enabled to true, IIS Express will start accepting client certificates:

<iisClientCertificateMappingAuthentication enabled="true">
            </iisClientCertificateMappingAuthentication>

You now need to restart Visual Studio and IIS Express. IIS Express can be restarted using the icon in your system tray.

From now on you will be asked for a client certificate and you can debug the whole application inside Visual Studio. This may not look like a big improvement, but trust me, it makes debugging much simpler.

Hope this could help someone else :-)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...