Disable SSL validation in Spring RestTemplate

Upasana | July 23, 2020 | 3 min read | 13,826 views


We will disable SSL certificate verification and thus trust all kind of certificates whether valid or not in Spring Boot RestTemplate.

In non production environments, we often need to disable ssl certificate validation (self-signed, expired, non trusted root, etc) for testing purpose. We will configure RestTemplate to disable SSL validation and allow http requests to these hosts without throwing exception.

RestTemplate can give any of the below error if SSL certificate of the target host is not valid:

PKIX path building failed: sun.security.provider.certpath
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.net.ssl.SSLHandshakeException: PKIX path building failed

Reasons for invalid SSL certificate could be many, including:

  • Expired certificate

  • Self-signed certificate

  • Wrong host information in certificates

  • Revoked certificate

  • Untrusted root of certificate

Gradle setup

We will be using Spring Boot 2 environment for this article, but you are free to choose any other compatible version of Spring.

build.gradle
plugins {
    id 'org.springframework.boot' version '2.3.1.RELEASE'
    id 'java'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}

group = 'com.shunya.tutorial'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.apache.httpcomponents:httpclient:4.5.10'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

We have added Apache HttpClient dependency to our project because that is required for customization of RestTemplate.

Creating RestTemplate Bean

Spring boot does not create any single auto-configured RestTemplate instance. It does, however, auto-configure a RestTemplateBuilder, which can be used to create RestTemplate instances when needed.

We will use RestTemplateBuilder to create a custom RestTemplate Bean that will trust all kind of (good or bad) SSL certificates. Please be aware this should never be done for any production environment.

RestTemplate Bean that trust all SSL certificates and does not verify hostname
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) throws NoSuchAlgorithmException, KeyManagementException {

        TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                    public void checkClientTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                }
        };  (1)
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); (2)
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();   (3)
        HttpComponentsClientHttpRequestFactory customRequestFactory = new HttpComponentsClientHttpRequestFactory();
        customRequestFactory.setHttpClient(httpClient);
        return builder.requestFactory(() -> customRequestFactory).build();  (4)
    }
}
1 Creating trust manager that blindly trusts all kind of SSL certificates (good ones as well as bad ones)
2 Install trust manager to SSL Context
3 Create an HttpClient that uses the custom SSLContext and do not verify cert hostname
4 Create a RestTemplate that uses custom request factory

If you do not want to use RestTemplateBuilder for configuring RestTemplate, then simply create a new instance of RestTemplate and pass it the customRequestFactory Object, as shown below:

...
class customRequestFactory = new HttpComponentsClientHttpRequestFactory();
        customRequestFactory.setHttpClient(httpClient);
return new RestTemplate(customRequestFactory);

Now you can autowire this RestTemplate Bean anywhere you want to use it.

A simple startup runner can be used to test the RestTemplate’s behaviour.

Application runner that makes Http request to bad SSL url
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class StartupRunner implements ApplicationRunner {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        final ResponseEntity<String> responseEntity = restTemplate.getForEntity("https://self-signed.badssl.com/", String.class);
        if(responseEntity.getStatusCode().is2xxSuccessful()) {
            System.out.println(responseEntity.getBody());
        }
    }
}

This shall not throw any error this time.

Creating self signed certificate for testing

Reference


Top articles in this category:
  1. Disable SSL verification in Spring WebClient
  2. Spring RestTemplate Basic Authentication
  3. Send Gupshup SMS using Java API
  4. Redis rate limiter in Spring Boot
  5. Download a file using Spring RestTemplate
  6. N+1 problem in Hibernate & Spring Data JPA
  7. Table backed global counter in spring hibernate

Recommended books for interview preparation:

Find more on this topic:
Buy interview books

Java & Microservices interview refresher for experienced developers.