Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignore self-signed certificates in Apache HTTPClient 4.5

I am trying to accept all certificates, and/or accept self-signed certificates using Apache HTTPClient version 4.5 (tutorial link here)

I've been going through solutions to this problem from a bunch of posts on SO. So far none of them have worked.

I keep getting this error: Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Apache Docs:

  • Apache v4.5 tutorial
  • SSL/TLS customization
  • Apache has a guide for version 3, but not version 4.

Related StackOverflow Questions - Here's some links of the solutions I've tried:

  • Ignoring SSL certificate in Apache HttpClient 4.3
  • How to ignore SSL certificate errors in Apache HttpClient 4.0
  • Ignore SSL Certificate Errors with Java
  • Need to trust all the certificates during the development using Spring
  • How to handle invalid SSL certificates with Apache HttpClient?

Note that in all these examples I am also passing a cookie store and a proxy credentials provider that I defined earlier. These are working, I'm just trying to add SSL support.

Try #1

Create my own ssl context with SSLContextBuilder and trust all self signed strategies with TrustSelfSignedStrategy.

SSLContextBuilder sshbuilder = new SSLContextBuilder();
sshbuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sshbuilder.build());

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #2

Same as above, but add a PoolingHttpClientConnectionManager

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", new PlainConnectionSocketFactory())
        .register("https", sslsf)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);//max connection

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .setConnectionManager(cm)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #3

Simply accept ALL certificates by overriding the TrustStrategy (this is not recommended)

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Try #4

I found something useful from this answer:

As of version 4.5 HttpClient disables SSLv3 protocol version by default

Here's the solution he gave:

SSLContext sslcontext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
        sslcontext, new String[] { "TLSv1", "SSLv3" }, null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.INSTANCE)
        .register("https", sslConnectionSocketFactory)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslConnectionSocketFactory)
    .setConnectionManager(cm)
    .build();

RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

like image 990
Katie Avatar asked Oct 07 '16 17:10

Katie


2 Answers

I'm using Apache HttpClient 4.5.3 and none of the above solutions helped. I always got the error

PKIX Path building failed

.

I found the solution in http://www.baeldung.com/httpclient-ssl

Here's my code:

try {
    SSLContext sslContext = new SSLContextBuilder()
            .loadTrustMaterial(null, (certificate, authType) -> true).build();
    httpClient = HttpClients.custom().setSSLContext(sslContext)
            .setSSLHostnameVerifier(new NoopHostnameVerifier())
            .build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
    e.printStackTrace();
}
like image 132
Martin Pabst Avatar answered Oct 02 '22 19:10

Martin Pabst


Very often you not only need to support self signed certificates, but also invoke multi-threaded requests, and so use a pooling connection manager. Here's how I do it:

private CloseableHttpClient newClient() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
    SSLContext context = SSLContexts.custom()
            .loadTrustMaterial(TrustSelfSignedStrategy.INSTANCE)
            .build();

    Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
            .register("http", PlainConnectionSocketFactory.INSTANCE)
            .register("https", new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE))
            .build();

    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);

    return HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();
}
like image 23
Yaniv Nahoum Avatar answered Oct 02 '22 19:10

Yaniv Nahoum