Игнорировать самозаверяющие сертификаты в AsyncClientHttp2Multiplexing

Я пытаюсь создать несколько асинхронных HTTP-соединений с использованием одной конечной точки клиента. Я пробовал пример мультиплексирования, приведенный на сайте Apache.

фрагмент кода выглядит следующим образом,

final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
            .setSoTimeout(Timeout.ofSeconds(5))
            .build();

    final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
            HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);

    client.start();

    final HttpHost target = new HttpHost("localhost", 7070, "https");
    final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
    final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
    try {
        final String[] requestUris = new String[] {"/test.html"};

        final CountDownLatch latch = new CountDownLatch(requestUris.length);
        for (final String requestUri: requestUris) {
            final SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
            endpoint.execute(
                    SimpleRequestProducer.create(request),
                    SimpleResponseConsumer.create(),
                    new FutureCallback<SimpleHttpResponse>() {

                        @Override
                        public void completed(final SimpleHttpResponse response) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + response.getCode());
                            System.out.println(response.getBody());
                        }

                        @Override
                        public void failed(final Exception ex) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + ex);
                        }

                        @Override
                        public void cancelled() {
                            latch.countDown();
                            System.out.println(requestUri + " cancelled");
                        }

                    });
        }
        latch.await();
    } finally {
        endpoint.releaseAndReuse();
    }

    System.out.println("Shutting down");
    client.shutdown(ShutdownType.GRACEFUL);

Этот пример работает правильно для сайта, который имеет действительный сертификат, но если я хочу попробовать сайт, сертификат которого истек / самоподписан, он выдает следующие исключения

javax.net.ssl.SSLHandshakeException: общая проблема SSLEngine javax.net.ssl.SSLHandshakeException: общая проблема SSLEngine в sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) в sun.security.ssl.SSLEngineImplck SSLEngineImpl.java:535) в sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214) в sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186) в javax.netng.wl. (SSLEngine.java:469) в org.apache.hc.core5.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:256) в org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:294) в org.apache.hc.core5.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:502) в org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:112) в орг.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) в org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) в org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) в org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80) в org.apache.hc.oror.orunor java:44) at java.lang.Thread.run(Thread.java:748). Вызывается: javax.net.ssl.SSLHandshakeException: общая проблема SSLEngine в sun.security.ssl.Alerts.getSSLException(Alerts.java:192) в sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) в sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) в sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) в sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) в sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) в sun.security.ssl.Handshaker.processjoop:1026) в sun.security.ssl.Handshaker$1.run(Handshaker.java:966) в sun.security.ssl.Handshaker$1.run(Handshaker.java:963) в java.security.AccessController.doPrivileged(нати) ve Method) в sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) в org.apache.hc.core5.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:274) в org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:331) ... еще 8 Вызвано: sun.security.validator.ValidatorException: сбой при построении пути PKIX: sun.security.provider.certpath.SunCertPathBuilderException: не удалось найти действительный путь сертификации к запрошенной цели в sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) в sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) в sun.security.validator.Validator.validate(Validator.java:260) в sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) в sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl. X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) в sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ... еще 16 причин: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификации к запрошенной цели в sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) в sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) в java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) в sun.secator.alidValid (Valid) Valid.java:392) ... еще 22

То, что я пробовал: я создал фабрику сокетов, которая доверяет всем сертификатам и попытался установить в connectionManager, но это создает CloseableHttpClient, и я думаю, что не может быть использован для асинхронного мультиплексирования, код выглядит следующим образом

SSLContext sslContext = SSLContextBuilder
                .create()
                .loadTrustMaterial(new TrustSelfSignedStrategy())
                .build();

        // we can optionally disable hostname verification. 
        // if you don't want to further weaken the security, you don't have to include this.
        HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

        // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
        // and allow all hosts verifier.
        SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

        Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create().register("https", connectionFactory).build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
        CloseableHttpClient build = HttpClients.custom().setConnectionManager(cm).build();

Пожалуйста, дайте мне знать, если есть какие-либо способы или обходные пути, чтобы игнорировать самозаверяющие сертификаты в MinimalHttpAsyncClient.

1 ответ

Решение

Прежде всего, настройте контекст SSL для использования вашим приложением. Настоятельно рекомендуется сделать так, чтобы он доверял только определенному самозаверяющему сертификату, если это абсолютно необходимо, вместо того, чтобы доверять всем сертификатам без разбора

final SSLContext sslContext = SSLContexts.custom()
        .loadTrustMaterial(new TrustAllStrategy())
        .build();

Создайте пользовательский менеджер соединений с заданным контекстом SSL

final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
        .setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
        .build();

Создать кастом HttpAsyncClient экземпляр с данным менеджером соединений

final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
       HttpVersionPolicy.FORCE_HTTP_2, 
       H2Config.DEFAULT, 
       null, 
       ioReactorConfig, 
       connectionManager);

В качестве альтернативы, если вы заботитесь только о HTTP/2 и не нуждаетесь в клиенте с запасным вариантом HTTP/1.1, рассмотрите возможность использования оптимизированных для HTTP/2 реализаций. Минимальная реализация обеспечит основные функции передачи сообщений (без управления состоянием, без аутентификации, без кэширования, без автоматических перенаправлений) с минимальными издержками.

final MinimalHttp2AsyncClient h2ClientMinimal = HttpAsyncClients.createHttp2Minimal(
      H2Config.DEFAULT, 
      ioReactorConfig, 
      new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE));

Полнофункциональная реализация обеспечит полнофункциональный транспорт HTTP/2 со всеми функциями, поддерживаемыми классическим HttpClient с единственным исключением декомпрессии прозрачного контента:

final HttpAsyncClient h2Client = HttpAsyncClients.customHttp2()
        .setIOReactorConfig(ioReactorConfig)
        .setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
        .build();

Надеюсь это поможет

Другие вопросы по тегам