Home > Net >  Apache HTTP Client SSL how acccept all certificates for testing purposes
Apache HTTP Client SSL how acccept all certificates for testing purposes

Time:03-05

I have a java cucumber test automation framework that I am using for testing apis.

Previously I was using a tool called Karate that has a simple flag ( karate.configure('ssl', { trustAll: true });) that allows you to trust all certificates.

I was hoping there would be a similar flag for use with Apache HTTP Client...but all my googling leads to long and complicated code.

This is the code I have written so far to send the .pfx file to the api

        String keyPassphrase = "";

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream("src/main/resources/sslCertificates/certificate.pfx"), keyPassphrase.toCharArray());

        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, null)
                .build();


        //This is the httpClient that you will use to send your http request
        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();

        //Send the request
        CloseableHttpResponse response = httpClient.execute(request);

but it gets rejected before it is sent saying

 "javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"

How can I easily accept all certificates to get around this problem? As stated I am just testing so there is no problem with doing this.

However I do have certificate files in .pfx and .crt formats and a client.key file that could potentially be used - but I don't know how.

CodePudding user response:

I used the solution mentioned in this post:

Getting Java to accept all certs over HTTPS

There, you build a custom TrustManager and HostNameVerifier to accept any certificate and domain:

Custom implementation of HostNameVerifier:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

public class TrustAllHostNameVerifier implements HostnameVerifier {

    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
}

Https connection creation:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    HttpsURLConnection.setHostnameVerifier(new TrustAllHostNameVerifier())
} catch (Exception e) {
  :
  :
}

Although you clarified that it's for testing purposes, it's important to remember that this is an extremely insecure solution where you lose all the protection given by the use of SSL.

CodePudding user response:

You can do the following if using HttpClient 4.4 or above (the example was taken from the reference below):

TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;
    SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, 
      NoopHostnameVerifier.INSTANCE);
    
    Registry<ConnectionSocketFactory> socketFactoryRegistry = 
      RegistryBuilder.<ConnectionSocketFactory> create()
      .register("https", sslsf)
      .register("http", new PlainConnectionSocketFactory())
      .build();

    BasicHttpClientConnectionManager connectionManager = 
      new BasicHttpClientConnectionManager(socketFactoryRegistry);
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
      .setConnectionManager(connectionManager).build();

More details here: https://www.baeldung.com/httpclient-ssl

CodePudding user response:

This code seems to have done the trick:

        String keyPassphrase = "";
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream("src/main/resources/sslCertificates/certificate.pfx"), keyPassphrase.toCharArray());
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, null);

        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                }
        };

        // Install the all-trusting trust manager
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());


        //This is the httpClient that you will use to send your http request
        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();

        //Send the request
        CloseableHttpResponse response = httpClient.execute(request);
  • Related