Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable SSL certificate checking with Spring RestTemplate?

I am trying to write an integration test where our test launches an embedded HTTPS server using Simple. I created a self-signed certificate using keytool and am able to access the server using a browser (specifically Chrome, and I do get a warning about the self-signed certificate).

However, when I try to connect using Spring RestTemplate, I get a ResourceAccessException:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8088":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; 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     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:557)     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)     at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:444)     at net.initech.DummySslServer.shouldConnect(DummySslServer.java:119)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)     at org.junit.runner.JUnitCore.run(JUnitCore.java:160)     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) Caused by: 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     at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)     at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1917)     at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301)     at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295)     at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369)     at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)     at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)     at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)     at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)     at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)     at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)     at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)     at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)     at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)     at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)     at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)     at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:52)     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:541)     ... 33 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target     at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)     at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)     at sun.security.validator.Validator.validate(Validator.java:260)     at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)     at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)     at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)     at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351)     ... 47 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target     at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)     at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)     at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)     at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)     ... 53 more 

From other questions and blog posts I've seen the advice to replace the HostnameVerifier with something like

private static final HostnameVerifier PROMISCUOUS_VERIFIER = ( s, sslSession ) -> true; 

And I've set it both globally and on the RestTemplate itself:

HttpsURLConnection.setDefaultHostnameVerifier( PROMISCUOUS_VERIFIER ); 

...and on the RestTemplate itself:

final RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory( new SimpleClientHttpRequestFactory() {     @Override     protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {         if(connection instanceof HttpsURLConnection ){             ((HttpsURLConnection) connection).setHostnameVerifier(PROMISCUOUS_VERIFIER);         }         super.prepareConnection(connection, httpMethod);     } }); 

Yet, I am still getting the above error. How can I get around it?

  1. Installing the certificate locally outside of the unit test is not an option as then it would need to get installed manually on every dev machine and build server and would cause an avalanche of red tape.
  2. We need SSL since we are testing a library that sits on top of RestTemplate and that we are configuring it correctly.

I am using Java 8 (but could use 7) and Spring 4.0.3 .

like image 655
Sled Avatar asked May 06 '14 21:05

Sled


People also ask

How do I disable SSL with RestTemplate?

To skip or avoid the SSL check, we need to modify the default RestTemplate available with the normal Spring package. In this configuration class, we basically declare a new Bean that creates a HTTPClient with the certificate check as disabled.

How do I disable certified check curl?

If you'd like to turn off curl's verification of the certificate, use the -k (or --insecure) option.


2 Answers

I wish I still had a link to the source that lead me in this direction, but this is the code that ended up working for me. By looking over the JavaDoc for X509TrustManager it looks like the way the TrustManagers work is by returning nothing on successful validation, otherwise throwing an exception. Thus, with a null implementation, it is treated as a successful validation. Then you remove all other implementations.

import javax.net.ssl.*; import java.security.*; import java.security.cert.X509Certificate;  public final class SSLUtil{      private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{             new X509TrustManager() {                 public java.security.cert.X509Certificate[] getAcceptedIssuers(){                     return null;                 }                 public void checkClientTrusted( X509Certificate[] certs, String authType ){}                 public void checkServerTrusted( X509Certificate[] certs, String authType ){}             }         };      public  static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {         // Install the all-trusting trust manager         final SSLContext sc = SSLContext.getInstance("SSL");         sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );         HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());     }      public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {         // Return it to the initial state (discovered by reflection, now hardcoded)         SSLContext.getInstance("SSL").init( null, null, null );     }      private SSLUtil(){         throw new UnsupportedOperationException( "Do not instantiate libraries.");     } } 
like image 58
Sled Avatar answered Sep 24 '22 09:09

Sled


For the sake of other developers who finds this question and need another solution that fits not only for unit-tests:

I've found this on a blog (not my solution! Credit to the blog's owner).

TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;  SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()         .loadTrustMaterial(null, acceptingTrustStrategy)         .build();  SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);  CloseableHttpClient httpClient = HttpClients.custom()         .setSSLSocketFactory(csf)         .build();  HttpComponentsClientHttpRequestFactory requestFactory =         new HttpComponentsClientHttpRequestFactory();  requestFactory.setHttpClient(httpClient);  RestTemplate restTemplate = new RestTemplate(requestFactory); 
like image 43
OhadR Avatar answered Sep 24 '22 09:09

OhadR