Does anyone have any friendly tips on how to perform client authentication via an x509 certificate using HTTPClient 4.0.1?
            Asked
            
        
        
            Active
            
        
            Viewed 3.3k times
        
    3 Answers
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);
 
    
    
        laz
        
- 28,320
- 5
- 53
- 50
- 
                    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. – hooknc Aug 18 '10 at 16:52
- 
                    2The above comment is no longer needed when working with the jdk 1.6.0_24 or later. – hooknc Apr 05 '11 at 15:43
- 
                    2For Apache HTTP Client 4.3+, see http://stackoverflow.com/a/26159543/340290 – manikanta Jul 11 '16 at 14:45
- 
                    2For Apache HTTP Client 4.4+, see http://stackoverflow.com/a/38313344/340290 – manikanta Jul 11 '16 at 18:02
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();
 }
 
    
    
        reto
        
- 16,189
- 7
- 53
- 67
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();
    }
}
 
    
    
        EpicPandaForce
        
- 79,669
- 27
- 256
- 428
- 
                    1@EvilRaat http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java from http://hc.apache.org/httpcomponents-client-4.3.x/examples.html – EpicPandaForce Jan 08 '15 at 09:04
 
    