Question

Is there a way to get the SSL certificate of the authenticated server using Apache HttpClient after the request - just the counterpart to request.getAttribute("javax.servlet.request.X509Certificate") on the server side?

Was it helpful?

Solution

Ok this is a bit meta in some respects and I'm hopefully doing this in a fashion that will work with any connection manager. I'm assuming you're running on the latest HttpClient (4.2)

So, what you will have to do is add an HttpResponseInterceptor to the client.

((AbstractHttpClient)client).addResponseInterceptor(new HttpResponseInterceptor() {
    @Override
    public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
        HttpRoutedConnection routedConnection= (HttpRoutedConnection)context.getAttribute(ExecutionContext.HTTP_CONNECTION);
        if( routedConnection.isSecure() ) {
            Certificate[] certificates= routedConnection.getSSLSession().getPeerCertificates();
            // Assume that PEER_CERTIFICATES is a constant you've defined
            context.setAttribute(PEER_CERTIFICATES, certificates);
        }
    }
});

Once that is done, any request made through this client will check to see if the connection is marked as 'secure' and then attempt to get the peer certificates.

In this example, I'm just putting in the entire array of certificates that were associated with the peer connection.

At this point, to execute you will do something similar to the following:

HttpContext context= new BasicHttpContext();
HttpGet get= new HttpGet(....);
client.execute(get, context);
// should contain the array of Certificate - these are more likely X509Certificate instances
Certificate[] peerCertificates= (Certificate[])context.getAttribute(PEER_CERTIFICATES);certificates
// do whatever logic to complete and consume the request

Hopefully that will get what you need - if anyone has suggestions beyond this they'd be appreciated.

EDIT This can also be done as a HttpRequestInterceptor and have the same effect as the connection is already established.

OTHER TIPS

For HttpClient 4.5 the solution needs to be changed like this:

clientBuilder.addInterceptorLast(new HttpResponseInterceptor() {
        @Override
        public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
            ManagedHttpClientConnection routedConnection = (ManagedHttpClientConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
            SSLSession sslSession = routedConnection.getSSLSession();
            if (sslSession != null) {
                Certificate[] certificates = sslSession.getPeerCertificates();
                // Assume that PEER_CERTIFICATES is a constant you've defined
                context.setAttribute(PEER_CERTIFICATES, certificates);
            }
        }
    });
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top