Recently i came across two SSL-related exceptions when writing a testing Spring-based client application using RestTemplate. Because both of them are related to an untrusted connection when making HTTPS calls (as a result of self-signed SSL certificate configured in Tomcat), and both have one common solution, i thought i’ll share it with You.
Exceptions thrown:
- java.security.cert.CertificateException: No name matching my.company.com found; nested exception is javax.net.ssl.SSLHandshakeException
- sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Solution:
- disabling SSL certificate validation (unless you want to go the “hard way” of installing a correct/SSL Authority-signed certificate)
- This is how i did it in Java:
import javax.net.ssl.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class SSLCertificateValidation { public static void disable() { try { SSLContext sslc = SSLContext.getInstance("TLS"); TrustManager[] trustManagerArray = { new NullX509TrustManager() }; sslc.init(null, trustManagerArray, null); HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new NullHostnameVerifier()); } catch(Exception e) { e.printStackTrace(); } } private static class NullX509TrustManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { System.out.println(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { System.out.println(); } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } private static class NullHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } } }
The complete example is available as a Gist.
What you now have to do, is to invoke SSLCertificateValidation.disable() prior to making a HTTPS call using RestClient. Simple as that.