Search code examples
javasslmockingkeystorehoverfly

Trusting Hoverfly java certificate programmatically


Using Hoverfly-java to mock web services in unit tests, and using HttpClient as web client, found that hoverfly proxy settings are propagated properly using useSystemProperties() however I still have TLS error: unknown certificate, I have to add certificate manually to keystore using

wget https://raw.githubusercontent.com/SpectoLabs/hoverfly/master/core/cert.pem
sudo $JAVA_HOME/bin/keytool -import -alias hoverfly -keystore $JAVA_HOME/jre/lib/security/cacerts -file cert.pem

I need Hoverfly SSL context to be added without the above two commands, I have tried:

CloseableHttpClient httpClient = httpClientBuilder.useSystemProperties().setSSLContext(SomeTestClass.hoverflyRule.getSslConfigurer().getSslContext()).build();

but still have TLS errors, any ideas?

I know it is possible to run above two commands from java code using ProcessBuilder but this will have security issues as it needs sudo access and unneeded vulnerability (that didn't work too).


Solution

  • After contacting Hoverfly support I had it work as follows

    CloseableHttpClient httpClient = HttpClients.custom()
                //.setConnectionManager(poolingConnectionManager) //this causes TLS errors so I commented it out until this final issue is solved.
                .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                .setDefaultRequestConfig(requestConfig)
                .setDefaultCredentialsProvider(credsProvider)
                .setDefaultHeaders(headers)
                .useSystemProperties()
                .build();
    

    I still have a problem on using setConnectionManager() (it causes TLS errors again), these are the settings I need to add for the newly created HttpCleint

    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
    poolingConnectionManager.setMaxTotal(1000);
    poolingConnectionManager.setDefaultMaxPerRoute(1000);
    

    UPDATE

    Solved issue, after searching and contacting hoverfly support I found similar problem, sol I solved it using

    private PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
        SSLConnectionSocketFactory sslsocketFactory = null;
        try {
            sslsocketFactory = new SSLConnectionSocketFactory(SSLContext.getDefault(), new DefaultHostnameVerifier());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                                                                    .register("https", sslsocketFactory)
                                                                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                                                                    .build();
    
        PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); 
        poolingConnectionManager.setMaxTotal(1000);
        poolingConnectionManager.setDefaultMaxPerRoute(1000);
        // Used these settings instead of constructor parameters (long timeToLive, TimeUnit timeUnit)
        poolingConnectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
    
        return poolingConnectionManager;
    }
    

    I wish Hoverfly could do all this hassle instead.