javaapache-httpclient-4.xapache-httpasyncclient

Apache Commons AsyncClient - Ignore Certificates - SSLPeerUnverifiedException


Thought I disabled checking certs in my Http Client, but keep getting SSLPeerUnverifiedException.

Here's my client:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ApacheCommonsAsyncClient implements IMakeHttpRequests {
    private static final Logger LOGGER = LoggerFactory.getLogger(PaxHttpClient.class);
    private static final int MAX_POOL_SIZE = 100;
    private static final int MAX_CONN_PER_ROUTE = 10;

    private final CloseableHttpAsyncClient httpClient;

    ApacheCommonsAsyncClient() {
        final RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000).setSocketTimeout(0).build();
        final Header doNotKeepAlive = new BasicHeader("Connection: keep-alive", "false");
        final Header closeConnection = new BasicHeader("Connection", "close");

        try {
            final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
                    new TrustSelfSignedStrategy());
            final ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
            final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);

            // @formatter:off
            this.httpClient = HttpAsyncClients.custom()
                    .setDefaultRequestConfig(requestConfig)
                    .setKeepAliveStrategy((httpResponse, httpContext) -> 0)
                    .setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
                    .setConnectionManager(cm)
                    .setSSLContext(sslContextBuilder.build())
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .setMaxConnTotal(MAX_POOL_SIZE)
                    .setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
                    .build();
            // @formatter:on

            this.httpClient.start();
        } catch (final GeneralSecurityException | IOReactorException e) {
            throw new RuntimeException(e);
        }
    }
}

Exception:

java.util.concurrent.ExecutionException: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
    at com.paxata.performance.App.run(App.java:30)
    at com.paxata.performance.Bootstrap.main(Bootstrap.java:43)
Caused by: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
    at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy.verifySession(SSLIOSessionStrategy.java:208)
    at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy$1.verify(SSLIOSessionStrategy.java:188)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:367)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:508)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:120)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
    at java.lang.Thread.run(Thread.java:748)

and the dependency versions i'm bringing in:

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpmime</artifactId>
        <version>4.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
        <version>4.4.9</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpasyncclient</artifactId>
        <version>4.1.3</version>
    </dependency>

Solution

  • Connection manager instance passed to the builder supersedes all connection management parameters such as SSL and pool settings.

    There are two ways it could be remedied.

    1. Let the builder construct and initialize a connection manager

    final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
            new TrustSelfSignedStrategy());
    this.httpClient = HttpAsyncClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setKeepAliveStrategy((httpResponse, httpContext) -> 0)
            .setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
            .setSSLContext(sslContextBuilder.build())
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .setMaxConnTotal(MAX_POOL_SIZE)
            .setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
            .build();
    
    1. Configure the connection manager prior to passing to the builder

    final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
            new TrustSelfSignedStrategy());
    final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(
            new DefaultConnectingIOReactor(), 
            RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", new SSLIOSessionStrategy(sslContextBuilder.build(), NoopHostnameVerifier.INSTANCE))
                .build());
    cm.setMaxTotal(MAX_POOL_SIZE);
    cm.setDefaultMaxPerRoute(MAX_CONN_PER_ROUTE);
    
    this.httpClient = HttpAsyncClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setKeepAliveStrategy((httpResponse, httpContext) -> 0)
            .setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
            .setConnectionManager(cm)
            .build();
    

    The former is recommended unless there are very strong reasons for doing the latter.

    PS: You do not want to disable connection persistence