1

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>
liltitus27
  • 1,670
  • 5
  • 29
  • 46

1 Answers1

1

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

ok2c
  • 26,450
  • 5
  • 63
  • 71
  • thanks @oleg, that resolved it. why do you recommend the former over the latter example? and why do you so strongly recommend against disabling connection persistence? i had to do that due to _very_ long-running requests (e.g., 37 hours) that would finish, but the client wouldn't get the responses unless i disabled connection persistence, oddly enough. – liltitus27 May 16 '18 at 14:20
  • 1
    You might want to limit the total time to live to something fairly short, but disabling connection persistence indiscriminately sounds too extreme to me – ok2c May 16 '18 at 20:12