在Apache HttpAsyncClient中配置SSL

Met*_*net 3 java ssl apache-httpcomponents apache-httpclient-4.x

我需要设置一个具有SSL支持的Apache HTTPAsyncClient。我使用此代码,但是它似乎不起作用(获取“ javax.net.ssl.SSLException:收到致命警报:handshake_failure”)

    System.setProperty("javax.net.debug", "ssl,handshake");
    System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

    KeyStore ts = KeyStore.getInstance("JKS");
    ts.load(loadStream("C:/TrustStore/cacerts"), "trustpass".toCharArray());
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(loadStream("C:/KeyStore/SSL/keystore.SomeKey"), "keypass".toCharArray());

    SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(ts).loadKeyMaterial(ks, "somekey".toCharArray()).setSecureRandom(new SecureRandom());        
    SSLContext ssl = sslBuilder.build();

    PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT));        

    CloseableHttpAsyncClient clientHttps = HttpAsyncClientBuilder.create()
            .setConnectionManager(cm)    
            .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
            .setSSLContext(ssl)
            .build();

    RequestConfig.Builder b = RequestConfig.custom();        
    b.setProxy(new HttpHost("proxyHost", proxyPort));
    RequestConfig rc = b.build();

    clientHttps.start();

    HttpRequestBase req = new HttpPost("https://someurl");
    ((HttpEntityEnclosingRequestBase)req).setEntity(new StringEntity("somestring"));
    req.setConfig(rc);

    clientHttps.execute(req, new FutureCallback<HttpResponse>() {

        @Override
        public void failed(Exception ex) {
            System.out.println(ex);
        }

        @Override
        public void completed(HttpResponse result) {
            System.out.println(result);                
        }

        @Override
        public void cancelled() {
            System.out.println("Cancelled");                
        }
    });    
Run Code Online (Sandbox Code Playgroud)

当使用javax.net.ssl.HttpsURLConnection实现此目的时,它可以工作(如果需要,我可以附加相关代码)。

编辑

基于@ ben75的答案,我终于使它与以下代码一起运行

System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

KeyStore ts = KeyStore.getInstance("JKS");
ts.load(loadStream("C:/TrustStore/cacerts"), "trustpass".toCharArray());
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(loadStream("C:/KeyStore/SSL/keystore.SomeKey"), "keypass".toCharArray());

SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(ts).loadKeyMaterial(ks, "somekey".toCharArray()).setSecureRandom(new SecureRandom());        
SSLContext ssl = sslBuilder.build();

SSLIOSessionStrategy s = new SSLIOSessionStrategy(ssl, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
RegistryBuilder<SchemeIOSessionStrategy> rb = RegistryBuilder.create();
rb.register("https", s).register("http", NoopIOSessionStrategy.INSTANCE);
PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT), rb.build());       

CloseableHttpAsyncClient clientHttps = HttpAsyncClientBuilder.create()
        .setConnectionManager(cm)
        .build();

RequestConfig.Builder b = RequestConfig.custom();        
b.setProxy(new HttpHost("proxyHost", proxyPort));
RequestConfig rc = b.build();

clientHttps.start();

HttpRequestBase req = new HttpPost("https://someurl");
((HttpEntityEnclosingRequestBase)req).setEntity(new StringEntity("somestring"));
req.setConfig(rc);

clientHttps.execute(req, new FutureCallback<HttpResponse>() {

    @Override
    public void failed(Exception ex) {
        System.out.println(ex);
    }

    @Override
    public void completed(HttpResponse result) {
        System.out.println(result);                
    }

    @Override
    public void cancelled() {
        System.out.println("Cancelled");                
    }
});    
Run Code Online (Sandbox Code Playgroud)

ben*_*n75 5

(我最近(在Android上)遇到了非常类似的问题,但我想您正在犯与我相同的错误。)

当您显式设置连接管理器时: builder.setConnectionManager(cm) sslContext被忽略。

您可以做的是将SSLContext注入PoolingNHttpClientConnectionManager中。

为此,可以使用以下构造函数: PoolingNHttpClientConnectionManager(org.apache.http.nio.reactor.ConnectingIOReactor ioreactor,注册表iosessionFactoryRegistry)

与iosessionFactoryRegistry一起包含一个SSLIOSessionStrategy构建以及SSLContext