13

Does anyone have any friendly tips on how to perform client authentication via an x509 certificate using HTTPClient 4.0.1?

3 Answers 3

21

Here is some code to get you going. The KeyStore is the object that contains the client certificate. If the server is using a self-signed certificate or a certificate that isn't signed by a CA as recognized by the JVM in the included cacerts file then you will need to use a TrustStore. Otherwise to use the default cacerts file, pass in null to SSLSockeFactory for the truststore argument..

import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; ... final HttpParams httpParams = new BasicHttpParams(); // load the keystore containing the client certificate - keystore type is probably jks or pkcs12 final KeyStore keystore = KeyStore.getInstance("pkcs12"); InputStream keystoreInput = null; // TODO get the keystore as an InputStream from somewhere keystore.load(keystoreInput, "keystorepassword".toCharArray()); // load the trustore, leave it null to rely on cacerts distributed with the JVM - truststore type is probably jks or pkcs12 KeyStore truststore = KeyStore.getInstance("pkcs12"); InputStream truststoreInput = null; // TODO get the trustore as an InputStream from somewhere truststore.load(truststoreInput, "truststorepassword".toCharArray()); final SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("https", new SSLSocketFactory(keystore, keystorePassword, truststore), 443)); final DefaultHttpClient httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpParams, schemeRegistry), httpParams); 
Sign up to request clarification or add additional context in comments.

4 Comments

This solution worked perfectly. Thank you for your assistance. FYI, due to SSL Handshake renegotiation issues I had to set the following virtual machine property: -Dsun.security.ssl.allowUnsafeRenegotiation=true I am/was working with java 1.6.0_20 and tomcat 6.0.29.
The above comment is no longer needed when working with the jdk 1.6.0_24 or later.
For Apache HTTP Client 4.3+, see stackoverflow.com/a/26159543/340290
For Apache HTTP Client 4.4+, see stackoverflow.com/a/38313344/340290
2

Another solution (copied from another example). I've used the same keystore for both 'trusting' (trustStore) and for authenticate myself (keyStore).

 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); FileInputStream instream = new FileInputStream(new File("miller.keystore")); try { trustStore.load(instream, "pw".toCharArray()); } finally { instream.close(); } SSLContext sslcontext = SSLContexts.custom() .loadTrustMaterial(trustStore) /* this key store must contain the certs needed & trusted to verify the servers cert */ .loadKeyMaterial(trustStore, "pw".toCharArray()) /* this keystore must contain the key/cert of the client */ .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); try { HttpGet httpget = new HttpGet("https://localhost"); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); } EntityUtils.consume(entity); } finally { response.close(); } } finally { httpclient.close(); } 

Comments

0

I used the following from a sample code on HttpClient's website (custom SSL context if I remember correctly).

{ KeyStore keyStore = KeyStore.getInstance("PKCS12"); //client certificate holder FileInputStream instream = new FileInputStream(new File( "client-p12-keystore.p12")); try { trustStore.load(instream, "password".toCharArray()); } finally { instream.close(); } // Trust own CA and all self-signed certs SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, "password".toCharArray()) // .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) //if you have a trust store .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients .custom() .setHostnameVerifier( SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) //todo .setSSLSocketFactory(sslsf).build(); try { HttpGet httpget = new HttpGet("https://localhost:8443/secure/index"); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); } EntityUtils.consume(entity); } finally { response.close(); } } finally { httpclient.close(); } } 

1 Comment

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.