Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How send different client certificates on different requests with a single instance of HttpClient in .Net Core?

The recommendation for HttpClient is to reuse a single instance. But from the API, it looks like the way to add certificates is on the instance, not per request. If we add two certificates, how can we make sure that "cert 1" is only sent to "one.somedomain.com", for example?

//A handler is how you add client certs (is there any other way?)
var _clientHandler = new HttpClientHandler();

//Add multiple certs
_clientHandler.ClientCertificates.Add(cert1);
_clientHandler.ClientCertificates.Add(cert2);
_clientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;


//Pretend this is our long-living HttpClient
var client = new HttpClient(_clientHandler);

//Now if we make a post request, will both certs be used?
using (HttpResponseMessage response = _client.PostAsync("https://one.somedomain.com", content).Result)
{
    //...elided...
 }
like image 650
Don Rhummy Avatar asked Nov 26 '22 23:11

Don Rhummy


1 Answers

Sorry. End of year a lot of work. Yo can try to implement somthing like this:

public class CustomHttpHandler : HttpClientHandler
{
    private readonly Dictionary<string, X509Certificate> _certMap;

    public CustomHttpHandler():base()
    {
        _certMap = new Dictionary<string, X509Certificate>() { { "server1name", new X509Certificate("cert1") }, { "server2name", new X509Certificate("cert2") } };
    }

    protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
    {
        string serverName = request.RequestUri.Host;
        if (ClientCertificates.Contains(_certMap[serverName]))
        {
            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                return response;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                throw;
            }
        }
        else
        {
            ClientCertificates.Clear();
            ClientCertificates.Add(_certMap[serverName]);

            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                return response;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadKey();
                throw;
            }
        }
    }
}

Just an idea, not tested it. Or, alternatively you can use Headers collection in RequestMessage instance. This article cover the topic: https://damienbod.com/2019/09/07/using-certificate-authentication-with-ihttpclientfactory-and-httpclient/

like image 158
Krivitskiy Grigoriy Avatar answered Nov 28 '22 12:11

Krivitskiy Grigoriy