HttpClient has long been popular for implementing outbound HTTP in Java. URL requests, HTTP remoting & service access are all common usecases.
For developers of HTTPS client applications, one scenario is common: wanting to test HTTPS connectivity, without needing a CA-signed certificate on each developer’s local appserver.
Developers can use a self-signed certificate on their server, but by default HttpClient (same as a web browser) will not accept untrusted connections. However, HttpClient’s SSL configuration can be modified to allow this.
Security aside, this technique is commonly done in earlier versions of HttpClient; but the configuration API (SSL configuration especially) API have changed radically in 4.4.
So, here’s how you can now accomplish this:
public HttpClient createHttpClient_AcceptsUntrustedCerts() { HttpClientBuilder b = HttpClientBuilder.create(); // setup a Trust Strategy that allows all certificates. // SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build(); b.setSslcontext( sslContext); // don't check Hostnames, either. // -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; // here's the special part: // -- need to create an SSL Socket Factory, to use our weakened "trust strategy"; // -- and create a Registry, to register it. // SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) .build(); // now, we create connection-manager using our Registry. // -- allows multi-threaded use PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry); b.setConnectionManager( connMgr); // finally, build the HttpClient; // -- done! HttpClient client = b.build(); return client; }
This technique is essentially a workaround for individual developers & local appservers.. Proper test environments should always be set up properly with a CA-signed certificate.
So, when we make an SSL connection but allow any certificates — what are we actually doing here, and how does this affect security?
Trust checks are the means to verify identity & authenticity of the remote server. Bypassing these means the connection itself is still encrypted, but we can no longer verify who we’re talking to — it could be a “spoofed DNS” imposter, or a “man-in-the-middle” attack capturing/ and later replaying the conversation.
Of course, in a development environment these attacks should largely be theoretical — if we’re talking to 127.0.0.1 we’re pretty safe.
This code is extracted from an actual working 4.4 implementation. Other answers for earlier HttpClient versions are popular, but just don’t work.. To save others having to spend hours figuring it out, I posted this.
Enjoy!
See also:
- The original answer on StackOverflow.
- Self-Signed Certificate Generator
- Wikipedia: self-signed certificates
Hello, and thank you !
You’re article helped me a lot !
Would you know how to specify a port for the SSL connections, in this solution ?
I was thinking Scheme would be good, but it’s deprecated in 4.4.
I’m loosing hope ^^
Don’t works. The method returns a CloseableHttpClient as type instead of HttpClient.
This code works fine. According the the HttpClient 4.4 source code, CloseableHttpClient implements HttpClient.
Maybe you have some old JAR version still in your classpath.. ?
This is deprecated in 4.4
SSLConnectionSocketFactory.
ALLOW_ALL_HOSTNAME_VERIFIERA workaround is to implement HostnameVerifier.verify method to return ‘true’ always.
Thanks for the tip Pankaj! HttpClient changes in 4.4 have been major.
We’re glad at least this one piece of API is still backwards compatible 🙂
The other option if you don’t need as much is to simply:
setSSLHostnameVerifier(new NoopHostnameVerifier())
when you’re building your client, i.e.:
CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext)
.setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
Thanks Adam. Good tip!
I’ve removed some more deprecation warnings coming with version 4.5. This is my (Scala) code:
private val httpClient: CloseableHttpClient = {
val trustStrategy = new TrustStrategy {
override def isTrusted(x509Certificates: Array[X509Certificate], s: String) = true
}
val sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build()
val sslSocketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier)
val socketFactoryRegistry =
RegistryBuilder.create[ConnectionSocketFactory]()
.register("http", PlainConnectionSocketFactory.getSocketFactory)
.register("https", sslSocketFactory)
.build()
val connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry)
HttpClients.custom()
.disableRedirectHandling()
.setSSLContext(sslContext)
.setConnectionManager(connectionManager)
.build()
}
The code from the former post looks better as a Gist.
I’m using 4.5, and nothing mentioned above worked for me. This, however, did:
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
(similar to what Adam wrote above).
Thanks a ton!
The code above is working well on 4.5 except the deprecation of SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
just replace:
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
with:
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
Adding .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) when build the httpClients doesn’t work for me.
Thanks a lot! Worked flawlessly.
It works like a charm!! Thank you!
Best,
JB
The same code removing the deprecated code and using the classes provided by httpclient and instantiating a restTemplate with authentication.
https://gist.github.com/bernalvarela/167441f1d357056b91ae36312c8debf9
Worked…
Thankx
Make your site wider or format your code in the 60 columns you can display.
Thanks for the suggestion Alex!
The above code is correct . I was able to turn off SSL certification using this.
Thanks
Well, I tried to reduce and delete deprecated tags:
class SSLClient {
static HttpClient getClient()
throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
return HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
}
}
You can call to SSLClient.getClient().execute(…)
HttpClient 4.5.8 used.
Regards,