[java] 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 .

This question is related to java spring resttemplate self-signed

The answer is


You can also register your keystore :

private void registerKeyStore(String keyStoreName) {
    try {
        ClassLoader classLoader = this.getClass().getClassLoader();
        InputStream keyStoreInputStream = classLoader.getResourceAsStream(keyStoreName);
        if (keyStoreInputStream == null) {
            throw new FileNotFoundException("Could not find file named '" + keyStoreName + "' in the CLASSPATH");
        }

        //load the keystore
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(keyStoreInputStream, null);

        //add to known keystore 
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keystore);

        //default SSL connections are initialized with the keystore above
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustManagers, null);
        SSLContext.setDefault(sc);
    } catch (IOException | GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}

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);

Here's a solution where security checking is disabled (for example, conversing with the localhost) Also, some of the solutions I've seen now contain deprecated methods and such.

/**
 * @param configFilePath
 * @param ipAddress
 * @param userId
 * @param password
 * @throws MalformedURLException
 */
public Upgrade(String aConfigFilePath, String ipAddress, String userId, String password) {
    configFilePath = aConfigFilePath;
    baseUri = "https://" + ipAddress + ":" + PORT + "/";

    restTemplate = new RestTemplate(createSecureTransport(userId, password, ipAddress, PORT));
    restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
    restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
 }

ClientHttpRequestFactory createSecureTransport(String username,
        String password, String host, int port) {
    HostnameVerifier nullHostnameVerifier = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(
            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), credentials);

    HttpClient client = HttpClientBuilder.create()
            .setSSLHostnameVerifier(nullHostnameVerifier)
            .setSSLContext(createContext())
            .setDefaultCredentialsProvider(credentialsProvider).build();

    HttpComponentsClientHttpRequestFactory requestFactory = 
            new HttpComponentsClientHttpRequestFactory(client);

    return requestFactory;
}

private SSLContext createContext() {
    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) {
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        SSLContext.setDefault(sc);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        return sc;

    } catch (Exception e) {
    }
    return null;
}

Please see below for a modest improvement on @Sled's code shown above, that turn-back-on method was missing one line, now it passes my tests. This disables HTTPS certificate and hostname spoofing when using RestTemplate in a Spring-Boot version 2 application that uses the default HTTP configuration, NOT configured to use Apache HTTP Client.

package org.my.little.spring-boot-v2.app;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Disables and enables certificate and host-name checking in
 * HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
 * Has no effect on implementations such as Apache Http Client, Ok Http.
*/
public final class SSLUtils {

    private static final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();

    private static final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession sslSession) {
            return true;
        }
    };

    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 {
        HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
        HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
        // Return it to the initial state (discovered by reflection, now hardcoded)
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, null, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    private SSLUtils() {
        throw new UnsupportedOperationException("Do not instantiate libraries.");
    }
}

@Bean(name = "restTemplateByPassSSL")
public RestTemplate restTemplateByPassSSL()
        throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
    HostnameVerifier hostnameVerifier = (s, sslSession) -> true;
    SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);

    return new RestTemplate(requestFactory);
}

In my case, with letsencrypt https, this was caused by using cert.pem instead of fullchain.pem as the certificate file on the requested server. See this thread for details.


Disabling certificate checking is the wrong solution, and radically insecure.

The correct solution is to import the self-signed certificate into your truststore. An even more correct solution is to get the certificate signed by a CA.

If this is 'only for testing' it is still necessary to test the production configuration. Testing something else isn't a test at all, it's just a waste of time.


Iknow It is too old to answer, but I couldn't find solution like this.

The code that worked for me with the jersey client:

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;

import javax.net.ssl.*;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

public class Testi {

static {
    disableSslVerification();
}
private static void disableSslVerification() {
    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}

public Testi() {
    MultivaluedHashMap<String, Object> headers = new MultivaluedHashMap<>();
    //... initialize headers

    Form form = new Form();
    Entity<Form> entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE);
    // initialize entity ...

    WebTarget target = getWebTarget();
    Object responseResult = target.path("api/test/path...").request()
            .headers(headers).post(entity, Object.class);

}

public static void main(String args[]) {
    new Testi();
}

private WebTarget getWebTarget() {
    ClientConfig clientConfig = new ClientConfig();
    clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 30000);
    clientConfig.property(ClientProperties.READ_TIMEOUT, 30000);

    SSLContext sc = getSSLContext();
    Client client = ClientBuilder.newBuilder().sslContext(sc).withConfig(clientConfig).build();
    WebTarget target = client.target("...url...");
    return target;
}

private SSLContext getSSLContext() {
    try {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }
        };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        return sc;
    } catch (NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
    }
    return null;
}
}

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to spring

Are all Spring Framework Java Configuration injection examples buggy? Two Page Login with Spring Security 3.2.x Access blocked by CORS policy: Response to preflight request doesn't pass access control check Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Spring Data JPA findOne() change to Optional how to use this? After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName The type WebMvcConfigurerAdapter is deprecated No converter found capable of converting from type to type

Examples related to resttemplate

RestClientException: Could not extract response. no suitable HttpMessageConverter found How to POST form data with Spring RestTemplate? Spring Resttemplate exception handling Could not autowire field:RestTemplate in Spring boot application RestTemplate: How to send URL and query parameters together How to autowire RestTemplate using annotations Multipart File Upload Using Spring Rest Template + Spring Web MVC Could not read JSON: Can not deserialize instance of hello.Country[] out of START_OBJECT token Get list of JSON objects with Spring RestTemplate How to disable SSL certificate checking with Spring RestTemplate?

Examples related to self-signed

Failed to load resource: net::ERR_INSECURE_RESPONSE How to disable SSL certificate checking with Spring RestTemplate? How to make a machine trust a self-signed Java application How to create a self-signed certificate for a domain name for development? How can I make git accept a self signed certificate? Getting Chrome to accept self-signed localhost certificate unsigned APK can not be installed How to export private key from a keystore of self-signed certificate