Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force Commons HTTPClient 3.1 to use TLS 1.2 only for HTTPS?

I wish to force Apache Commons HTTP-Client (version 3.1) to use TLS 1.2 as the only protocol for HTTPS.

This is due to the server supposedly being upgraded to TLS 1.2 and not accepting any older protocol anymore (causing 'Connection Reset' to be returned).

For further context, probably irrelevant, the HTTP-Client is used along with Axis2 to make a SOAP; some of the code used for setting up the HttpClient is below:

MultiThreadedHttpConnectionManager connMgr = new MultiThreadedHttpConnectionManager();
this.httpClient = new HttpClient(connMgr);

// initialize HttpClient parameters
HttpClientParams hcParams = this.httpClient.getParams();

// Maximum time to wait to receive connection from pool
hcParams.setConnectionManagerTimeout(this.maxWait);
hcParams.setSoTimeout(this.timeout);
hcParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(this.retryCount, false));

// Initialize global Connection manager parameters
HttpConnectionManagerParams cmParams = connMgr.getParams();
cmParams.setDefaultMaxConnectionsPerHost(this.maxActive);
cmParams.setStaleCheckingEnabled(this.checkStaleConnections);
cmParams.setConnectionTimeout(this.timeout);

Thanks a lot for the help!

like image 263
abdelrahman-sinno Avatar asked Sep 15 '15 13:09

abdelrahman-sinno


People also ask

Does HttpClient use TLS?

You need TLS 1.2+ support for HttpClient . You don't need TLS 1.2+ support for WebClient .

What is SSLConnectionSocketFactory?

SSLConnectionSocketFactory is a layered socket factory for TSL and SSL connections. Using this, you can verify the Https server using a list of trusted certificates and authenticate the given Https server. You can create this in many ways.

Does HttpClient need to be closed?

You do not need to explicitly close the HttpClient, however, (you may be doing this already but worth noting) you should ensure that connections are released after method execution. Edit: The ClientConnectionManager within the HttpClient is going to be responsible for maintaining the state of connections.


2 Answers

Too bad nobody answered; I was able to do it, first you write a CustomHttpSocketFactory, then you do:

String scheme = "https"; Protocol baseHttps = Protocol.getProtocol(scheme); int defaultPort = baseHttps.getDefaultPort();  ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory(); ProtocolSocketFactory customFactory = new CustomHttpsSocketFactory(baseFactory);  Protocol customHttps = new Protocol(scheme, customFactory, defaultPort); Protocol.registerProtocol(scheme, customHttps);  

A sample custom socket factory code is found here, but instead I did:

public class CustomHttpsSocketFactory implements SecureProtocolSocketFactory {     private final SecureProtocolSocketFactory base;     public CustomHttpsSocketFactory(ProtocolSocketFactory base)    {       if(base == null || !(base instanceof SecureProtocolSocketFactory)) throw new IllegalArgumentException();       this.base = (SecureProtocolSocketFactory) base;    }     private Socket acceptOnlyTLS12(Socket socket)    {       if(!(socket instanceof SSLSocket)) return socket;       SSLSocket sslSocket = (SSLSocket) socket;       sslSocket.setEnabledProtocols(new String[]{"TLSv1.2" });       return sslSocket;    }     @Override    public Socket createSocket(String host, int port) throws IOException    {       return acceptOnlyTLS12(base.createSocket(host, port));    }    @Override    public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException    {       return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort));    }    @Override    public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException    {       return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort, params));    }    @Override    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException    {       return acceptOnlyTLS12(base.createSocket(socket, host, port, autoClose));    }  } 
like image 80
abdelrahman-sinno Avatar answered Oct 07 '22 19:10

abdelrahman-sinno


You need a Socket reference in your code. Then you can set enabled protocols on it like this:

if (socket != null && (socket instanceof SSLSocket)) {
    ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
}
like image 36
IgorGanapolsky Avatar answered Oct 07 '22 18:10

IgorGanapolsky