Search code examples
spring-boothttpsssl-certificateresttemplatetls1.2

Verify Certificate and Hostname for an HTTPS REST call with Spring RestTemplate


I have a Spring Boot Microservice where I am trying to invoke an external server which exposes an HTTPS REST Endpoint (TLS v1.2). I have been provided the server side certificate in .pem format.

I would like to implement this call using RestTemplate and use the provided certificate and verify the host name during the call.

I have tried to Google this and all the search results are trying to ignore the certificate and host name.

Can I have an example code snippet to implement this properly?


Solution

  • After some digging with different blogs and stackoverflow threads, following worked for me:

    Create Rest Template:

    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    keyStore.load(new FileInputStream(ResourceUtils.getFile(clientKeyPath)), "".toCharArray());
    
    SSLContext sslContext = SSLContextBuilder
                    .create()
                    .loadKeyMaterial(keyStore, null)
                    .loadTrustMaterial(ResourceUtils.getFile(keystorePath), keystorePassword.toCharArray())
                    .build();
    
    SSLConnectionSocketFactory sslConnectionSocketFactory = new  SSLConnectionSocketFactory(sslContext, new CustomHostnameVerifier());
    
    HttpClient client = HttpClients
                    .custom()
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .build();
    
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    
    requestFactory.setHttpClient(client);
    
    RestTemplate sslRestTemplate = new RestTemplate(requestFactory);
    

    Implementation of CustomHostnameVerifier:

    @Component
    public class CustomHostnameVerifier implements HostnameVerifier {
    
        @Value("${dns.name}")
        private String dnsName;
    
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return hostname.equals(dnsName);
        }
    }