Apache Commons AsyncClient - 忽略证书 - SSLPeerUnverifiedException

时间:2018-05-15 20:20:25

标签: java apache-httpclient-4.x apache-httpasyncclient

我以为我在我的Http客户端中禁用了检查证书,但继续获取SSLPeerUnverifiedException

这是我的客户:

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);
        }
    }
}

例外:

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)

和我带来的依赖版本:

    <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>

1 个答案:

答案 0 :(得分:1)

传递给构建器的连接管理器实例取代所有连接管理参数,例如SSL和池设置。

有两种方法可以补救。

  1. 让构建器构建并初始化连接管理器
  2. 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. 在传递到构建器之前配置连接管理器
    2. 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();
      

      除非有充分的理由去做后者,否则建议使用前者。

      PS:您不希望禁用连接持久性