Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuring SSL in Apache HttpAsyncClient

I need to setup an Apache HTTPAsyncClient with SSL support. I use this code, but it doesn't seem to work (getting "javax.net.ssl.SSLException: Received fatal alert: 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");                
        }
    });    

When using the javax.net.ssl.HttpsURLConnection to achive this, it works (I can attach the relevant code, if needed).

EDIT

Based on @ben75 answer, I finally make it running with the following code

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");                
    }
});    
like image 220
MetaHnet Avatar asked Feb 01 '15 13:02

MetaHnet


People also ask

How does Apache HttpClient handle invalid SSL certificates?

To resolve the issue, do one of the following: Configure SSLContext with a TrustManager that accepts any certificate (see below). Configure SSLContext with an appropriate trust store that includes your certificate. Add the certificate for that site to the default Java trust store.

Does HttpClient support https?

C# Only http and https schemes are allowed - HttpClient - Microsoft Q&A.

What is Apache httpasyncclient used for?

Overview In this tutorial we'll illustrate the most common use cases of the Apache HttpAsyncClient – from basic usage, to how to set up a proxy, how to use SSL certificate and finally – how to authenticate with the async client. 2. Simple Example First – let's see how to use HttpAsyncClient in a simple example – send a GET request:

What is SSL context in Apache httpclient?

Apache HttpClient - Custom SSL Context - Using Secure Socket Layer, you can establish a secured connection between the client and server. It helps to safeguard sensitive information such as credit card

How do I enable SSL in Apache?

Apache SSL Configuration. And a final step would be to configure Apache so it can serve the request over HTTPS. Login to the Apache web server. Take a backup of httpd.conf file (default location /usr/local/apache2/conf/) Open the file with the vi editor and ensure mod_ssl module & httpd-ssl.conf exists and not commented.

How to configure Apache to serve a request over HTTPS?

And a final step would be to configure Apache so it can serve the request over HTTPS. Login to the Apache web server. Take a backup of httpd.conf file (default location /usr/local/apache2/conf/) Open the file with the vi editor and ensure mod_ssl module & httpd-ssl.conf exists and not commented.


2 Answers

(I run in very similar problem recently (on Android) but I guess you are making the same error as I did.)

When you set a connection manager explicitly : builder.setConnectionManager(cm) the sslContext is ignored.

What you can do is inject your SSLContext in the PoolingNHttpClientConnectionManager.

To do so, you can use this constructor : PoolingNHttpClientConnectionManager(org.apache.http.nio.reactor.ConnectingIOReactor ioreactor, Registry iosessionFactoryRegistry)

with iosessionFactoryRegistry containing an SSLIOSessionStrategy build with your SSLContext

like image 156
ben75 Avatar answered Sep 30 '22 08:09

ben75


Here is a working example:

public SSLContext getSSLContext() {
    final TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
    try {
        final SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        sslContext.getServerSessionContext().setSessionCacheSize(1000);
        return sslContext;
    } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
    }
    return null;
}

public Registry<SchemeIOSessionStrategy> getSSLRegistryAsync() {
    return RegistryBuilder.<SchemeIOSessionStrategy>create()
            .register("http", NoopIOSessionStrategy.INSTANCE)
            .register("https", new SSLIOSessionStrategy(
                    getSSLContext(), null, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)).build();
}

public PoolingNHttpClientConnectionManager getPoolingNHttpClientConnectionManager() {
    try {
        final PoolingNHttpClientConnectionManager connectionManager =
                new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT), getSSLRegistryAsync());
        connectionManager.setMaxTotal(connectionPoolMax);
        connectionManager.setDefaultMaxPerRoute(connectionPoolMaxPerRoute);

        return connectionManager;
    } catch (IOReactorException e) {
    }
    return null;
}

public RequestConfig getRequestConfig() {
    return RequestConfig.custom()
            .setConnectTimeout(connectTimeout)
            .setSocketTimeout(socketTimeout)
            .setConnectionRequestTimeout(socketTimeout)
            .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
            .build();
}

public CloseableHttpAsyncClient getHttpAsyncClient() {
    final CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()
            .setConnectionManager(getPoolingNHttpClientConnectionManager())
            .setDefaultRequestConfig(getRequestConfig())
            .build();
    return httpAsyncClient;
}
like image 20
Gagandeep Kalra Avatar answered Sep 30 '22 10:09

Gagandeep Kalra