简体   繁体   中英

C#, .Net Core Private key authentication httpClient

We are having a problem with a friend with loading a private certificate to httpHandler.
We are using .net core and need to host all aplication in the cloud.
Main goal is to get message from SQS and perform some specified API shots after with consumed data.
We have a problem with certificate with public / private key. We have tried I think all the possible ways of loading it.

    public async Task<HttpResponseMessage> VisitHttps()
    {
        // Proceed for an invalid cerficate
        ServicePointManager.ServerCertificateValidationCallback +=
        (sender, certificate, chain, sslPolicyErrors) => true;

        // Add the certificate
        var handler = new HttpClientHandler();
        var cert = GetMyCert();
        if (cert != null)
        {
            handler.ClientCertificates.Add(cert);
            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
            handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
            //handler.PreAuthenticate = true;
        }
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;


        HttpClient cclient = new HttpClient(handler)
        {
            //BaseAddress = new Uri("https://someurl.com")

        };
        cclient.DefaultRequestHeaders.Accept.Clear();
        cclient.DefaultRequestHeaders.Accept.Add(new 

MediaTypeWithQualityHeaderValue("application/json"));
            return await cclient.GetAsync("https://some-url.com/ping"); }

And the method GetMyCert() looks like below:

string currentLocation = $"{AppDomain.CurrentDomain.BaseDirectory}key-public.crt";
                //var xcert = new X509Certificate2(currentLocation, "password");

                ////var currentLocationPriv = $"{AppDomain.CurrentDomain.BaseDirectory}key-private.crt";
                ////var privcert = new X509Certificate2(currentLocationPriv, "password", X509KeyStorageFlags.EphemeralKeySet);
                //var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                //certStore.Open(OpenFlags.ReadWrite);
                //certStore.Add(xcert);
                //certStore.Close();
            //return xcert;

            X509Store store = new X509Store("My", StoreLocation.CurrentUser);
            X509Certificate2 cert;
            cert = new X509Certificate2(File.ReadAllBytes(currentLocation), "password", X509KeyStorageFlags.MachineKeySet);
            bool result = cert.Verify();
            var r2 = result;
            return cert;

commented lines are variances of what we have tried to do.
We have no idea what else we should try to handle this issue.
Any guidelines would be more than welcome

EDIT:
I've tried registering this inside startup class but it seems not working anyway. I always got the private key field inside certificate empty. And hasPrivateKey marked as false.

 private void CreateCert(IServiceCollection services)
    {
        string currentLocation = $"{AppDomain.CurrentDomain.BaseDirectory}key-public.crt";
        var certificate = new X509Certificate2(currentLocation, "password");
        services.AddHttpClient("TestClient", client =>
        {
            client.BaseAddress = new Uri("https://someurl.com");
        })
        .ConfigurePrimaryHttpMessageHandler(() =>
            {
            var handler = new HttpClientHandler();
            handler.ClientCertificates.Add(certificate);
            return handler;
        });
    }  

My Test code:

        [Fact]
    public async Task ShouldPong()
    {
        var testClient = new TestClient()
        {
            BaseAddress = new Uri("https://someurl.com")
        };
        var result = await testClient.GetAsync("/ping");
        result.StatusCode.Should().Be(HttpStatusCode.OK);
    }

TestClient:

public class TestClient : HttpClient
{
    public TestClient()
        :base()
    {

    }

    public TestClient(HttpMessageHandler handler)
        : base(handler)
    {

    }
}  

EDIT:
The problem was solved when changing the .crt files into a .pfx file. Since the API we was hitting was hosted on nginx.

The problem was resolved by creating a .PFX file. The server we were hitting was hosted on nginx that requires .pfx format. The .crt files are PEM certificate that was not valid for nginx.

I think you're not instantiating the client correctly, accordingly with the doc for Named Clients .

You will need to receive the IHttpClientFactory in run-time and ask for your named client like this:

 var client = _clientFactory.CreateClient("TestClient");

About testing with Dependency Injection, I believe this Microsoft tutorial can help: Integration Tests Asp.Net Core . The deal here is, as the Startup.cs file and the Core Dependency Injector are part of the framework, you need to setup simulate the web application in the test context. And Microsoft provides the WebApplicationFactory for that.

This example demonstrate a test with a httpClient given by the IHttpClientFactory in a simulated web application environment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM