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!
You need TLS 1.2+ support for HttpClient . You don't need TLS 1.2+ support for WebClient .
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.
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.
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)); } }
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"});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With