简体   繁体   中英

MTLS and http client connection pool usage

Background

  • I am required to connect to a server for various clients.
  • Each client connection should use a unique TLS cert.
  • MTLS is in place on the server.
  • I want to use connection pooling to improve latency.

Using the following http client

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.12</version>
</dependency>

My Assumption When managing connections in the connection pool, when a connection is being selected the client certificate should be considered before selecting the same connection in the connection pool. I do not want connections for clientA using clientB TLS cert and vice versa.

Question Is this assumption true?

Scenario 1)

I have max connections per route set to 2. I make a call to the MTLS secured server for client A. (one connection in the pool) I make a call to the MTLS secured server for client A. (two connections in the pool) Should this not of reused the first connection?

Scenario 2)

I have max connections per route set to 2. I make a call to the MTLS secured server for client A. (one connection in the pool) I make a call to the MTLS secured server for client B. (two connections in the pool)

However the second call does not seem to carry out a full handshake an is using clientA certificate.

I would expect the second call to require a full handshake and the connections to be not related in anyway.

Is this the expected behaviour? Am I missing something obvious here?

Updated simpler test case

We are now using the http context so I have attached the updated logs. I have simplified the test case too and now it connects to the same server twice each time it should use a different client certificate.

The application is using spring boot and has a single restTemplate and single httpClient.

Its using a PrivateKeyStrategy to decide what private key/certificate to use when communicating with the server.

The first connection uses key alias 'e2e_transport_key_id_franek' (you will see this in the logs)

The second connection should use alias 'e2e_transport_key_id_pdw' (never seen in the logs)

The second connection we are making should use the key/cert with alias 'e2e_transport_key_id_pdw' however the session is resumed see line 448 Try resuming session. Which means we cannot use the PrivateKeyStrategy to pick the client certificate to use.

How to force the client connection to not reuse the session for connections we intend to use a different client certificate for?

client logs https://pastebin.com/zN0EW3Qy

Is this assumption true?

Your assumption is right. The methods of a connection pool for requesting and releasing a connection take both an additional argument with the name state . This state argument usually takes a user token or null if no authentication is in place.

A connection can only be re-used when it is requested with the same user token that was used to release the connection back into the connection pool.

This mechanism works also for SSL client certificates. After a successful SSL handshake an SSL connection is released together with an X500Principal representing the user token. This token is also stored in the HttpContext object that is used for the request. To re-use the released connection in subsequent HTTP requests you have also to re-use the HttpContext of the first HTTP request.

Scenario 1

clientA.execute(new HttpGet("..."));
clientA.execute(new HttpGet("..."));

The first request triggers a full SSL handshake. The connection is released with the user token. The second request uses a new HttpContext which does not contain any user token. Therefore the connection within the pool cannot be re-used and a new connection is created with a full handshake.

Scenario 2

HttpContext context = new HttpClientContext();
clientA.execute(new HttpGet("..."), context);
clientB.execute(new HttpGet("..."), context);

As explained before, the user token is stored within the HttpContext . So if you re-use the HttpContext from the first request the second request can re-use the already existing connection even when you use a different client with a different connection factory / client certificate. If the connection should be in use a new connection would be created with the connection factory of clientB.

To separate clientA and clientB and to ensure that connections are only re-used per client, you have to use one HttpContext per client and re-use the context for every request:

HttpContext contextA = new HttpClientContext();
clientA.execute(new HttpGet("..."), contextA);
clientA.execute(new HttpGet("..."), contextA);

HttpContext contextB = new HttpClientContext();
clientB.execute(new HttpGet("..."), contextB);

Please note that in case of a session timeout or a requested renegotiation a full handshake may also be required even when a connection gets reused.

Is this assumption true?

Your assumption is correct. HttpClient 4 and 5 are capable of tracking user specific state associated with HTTP connections (NTLM context, TLS user identity, etc) and take it into account when re-using persistent connections.

Scenario 1)

The latter call should re-use the existing connection, as long as it shares the same execution context with the former.

Scenario 2)

No, it is not. Please provide a complete context / wire log of the session exhibiting the problem and I will try to figure out the reason.

http://hc.apache.org/httpcomponents-client-4.5.x/logging.html

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