Disabling SSL Certificate Validation in Spring RestTemplate

SpringValidationSsl CertificateResttemplate

Spring Problem Overview


I am having two Spring-based web apps A and B, on two different machines.

I want to make an HTTPS call from web app A to web app B, however, I am using a self-signed certificate in Machine B. So my HTTPS request fails.

How can I disable HTTPS certificate validation when using RestTemplate in Spring? I want to disable validation because both web app A and B are within the internal network, but data transfer has to happen over HTTPS

Spring Solutions


Solution 1 - Spring

@Bean
public RestTemplate restTemplate() 
                throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    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);
    return restTemplate;
 }

Solution 2 - Spring

Essentially two things you need to do are use a custom TrustStrategy that trusts all certs, and also use NoopHostnameVerifier() to disable hostname verification. Here is the code, with all the relevant imports:

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
	TrustStrategy acceptingTrustStrategy = (x509Certificates, s) -> true;
    SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
	RestTemplate restTemplate = new RestTemplate(requestFactory);
	return restTemplate;
}

Solution 3 - Spring

What you need to add is a custom HostnameVerifier class bypasses certificate verification and returns true

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
});

This needs to be placed appropriately in your code.

Solution 4 - Spring

Add my response with cookie :

public static void main(String[] args) {
     MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
     params.add("username", testUser);
     params.add("password", testPass);
     NullHostnameVerifier verifier = new NullHostnameVerifier(); 
     MySimpleClientHttpRequestFactory requestFactory = new MySimpleClientHttpRequestFactory(verifier , rememberMeCookie);
     ResponseEntity<String> response = restTemplate.postForEntity(appUrl + "/login", params, String.class);

     HttpHeaders headers = response.getHeaders();
     String cookieResponse = headers.getFirst("Set-Cookie");
     String[] cookieParts = cookieResponse.split(";");
     rememberMeCookie = cookieParts[0];
     cookie.setCookie(rememberMeCookie);

     requestFactory = new  MySimpleClientHttpRequestFactory(verifier,cookie.getCookie());
          restTemplate.setRequestFactory(requestFactory);
}
    
    
public class MySimpleClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    	
    	private final HostnameVerifier verifier;
    	private final String cookie;
    	
    	public MySimpleClientHttpRequestFactory(HostnameVerifier verifier ,String cookie) {
    		this.verifier = verifier;
    		this.cookie = cookie;
    	}
    	
    	@Override
    	protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
    		if (connection instanceof HttpsURLConnection) {
    			((HttpsURLConnection) connection).setHostnameVerifier(verifier);
    			((HttpsURLConnection) connection).setSSLSocketFactory(trustSelfSignedSSL().getSocketFactory());
    			((HttpsURLConnection) connection).setAllowUserInteraction(true);
    			String rememberMeCookie = cookie == null ? "" : cookie; 
    			((HttpsURLConnection) connection).setRequestProperty("Cookie", rememberMeCookie);
    		}
    		super.prepareConnection(connection, httpMethod);
    	}
    	
    	public SSLContext trustSelfSignedSSL() {
    		try {
    			SSLContext ctx = SSLContext.getInstance("TLS");
    			X509TrustManager tm = new X509TrustManager() {
    				
    				public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    				}
    				
    				public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    				}
    				
    				public X509Certificate[] getAcceptedIssuers() {
    					return null;
    				}
    			};
    			ctx.init(null, new TrustManager[] { tm }, null);
    			SSLContext.setDefault(ctx);
    			return ctx;
    		} catch (Exception ex) {
    			ex.printStackTrace();
    		}
    		return null;
    	}
    	
    }
    
    
    public class NullHostnameVerifier implements HostnameVerifier {
    	   public boolean verify(String hostname, SSLSession session) {
    	      return true;
    	   }
    	}

Solution 5 - Spring

I found a simple way

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

Imports used

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

Solution 6 - Spring

You can use this with HTTPClient API.

public RestTemplate getRestTemplateBypassingHostNameVerifcation() {
	CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
	HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
	requestFactory.setHttpClient(httpClient);
	return new RestTemplate(requestFactory);

}

Solution 7 - Spring

Complete code to disable SSL hostname verifier,

RestTemplate restTemplate = new RestTemplate();
//to disable ssl hostname verifier
restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory() {
   @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
    	if (connection instanceof HttpsURLConnection) {
    		((HttpsURLConnection) connection).setHostnameVerifier(new NoopHostnameVerifier());
        }
	    super.prepareConnection(connection, httpMethod);
	}
});

Solution 8 - Spring

Another way to do that trick very simple without import any APACHE or Any unknow package.

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

    private void ignoreCertificates() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] certs, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
     

    }

and set ignoreCertificates() before RestTemplate:

   ignoreCertificates();
   RestTemplate restTemplate = new RestTemplate();

Solution 9 - Spring

To overrule the default strategy you can create a simple method in the class where you are wired your restTemplate:

 protected void acceptEveryCertificate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

    TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            return true;
        }
    };
    
    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(
            HttpClientBuilder
                    .create()
                    .setSSLContext(SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build())
                    .build()));
}

Note: Surely you need to handle exceptions since this method only throws them further!

Solution 10 - Spring

This problem is about SSL connection. When you try to connect to some resource https protocol requires to create secured connection. That means only your browser and website server know what data is being sent in requests bodies. This security is achieved by ssl certificates that stored on website and are being downloaded by your browser (or any other client, Spring RestTemplate with Apache Http Client behind in our case) with first connection to host. There are RSA256 encryption and many other cool things around. But in the end of a day: In case certificate is not registered or is invalid you will see certificate error (HTTPS connection is not secure). To fix certificate error website provider need to buy it for particular website or fix somehow e.g. https://www.register.com/ssl-certificates

Right way how problem can be solved

  • Register SSL certificate

Not a right way how problem can be solved

  • download broken SSL certificate from website

  • import SSL certificate to Java cacerts (certificate storage)

    keytool -importcert -trustcacerts -noprompt -storepass changeit -alias citrix -keystore "C:\Program Files\Java\jdk-11.0.2\lib\security\cacerts" -file citrix.cer

Dirty (Insecure) way how problem can be solved

  • make RestTemplate to ignore SSL verification

      @Bean
      public RestTemplateBuilder restTemplateBuilder(@Autowired SSLContext sslContext) {
          return new RestTemplateBuilder() {
              @Override
              public ClientHttpRequestFactory buildRequestFactory() {
                  return new HttpComponentsClientHttpRequestFactory(
                          HttpClients.custom().setSSLSocketFactory(
                                  new SSLConnectionSocketFactory(sslContext
                                          , NoopHostnameVerifier.INSTANCE)).build());
              }
          };
      }
    
      @Bean
          public SSLContext insecureSslContext() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
             return SSLContexts.custom()
                      .loadTrustMaterial(null, (x509Certificates, s) -> true)
                      .build();
          }
    

Solution 11 - Spring

Security: disable https/TLS certificate hostname check,the following code worked in spring boot rest template

*HttpsURLConnection.setDefaultHostnameVerifier(
		//SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
		// * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.NoopHostnameVerifier}
		new NoopHostnameVerifier()
);*

Solution 12 - Spring

Java code example for HttpClient > 4.3

package com.example.teocodownloader;

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class Example {
    public static void main(String[] args) {
        CloseableHttpClient httpClient
                = HttpClients.custom()
                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory
                = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
    }
}

By the way, don't forget to add the following dependencies to the pom file:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
</dependency>

You could find Java code example for HttpClient < 4.3 as well.

Solution 13 - Spring

If you are using rest template, you can use this piece of code

    fun getClientHttpRequestFactory(): ClientHttpRequestFactory {
        val timeout = envTimeout.toInt()
        val config = RequestConfig.custom()
            .setConnectTimeout(timeout)
            .setConnectionRequestTimeout(timeout)
            .setSocketTimeout(timeout)
            .build()

        val acceptingTrustStrategy = TrustStrategy { chain: Array<X509Certificate?>?, authType: String? -> true }

        val sslContext: SSLContext = SSLContexts.custom()
            .loadTrustMaterial(null, acceptingTrustStrategy)
            .build()

        val csf = SSLConnectionSocketFactory(sslContext)

        val client = HttpClientBuilder
            .create()
            .setDefaultRequestConfig(config)
            .setSSLSocketFactory(csf)
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build()
        return HttpComponentsClientHttpRequestFactory(client)
    }

    @Bean
    fun getRestTemplate(): RestTemplate {
        return RestTemplate(getClientHttpRequestFactory())
    }

Solution 14 - Spring

@Bean
public RestTemplate restTemplate() throws Exception {
    SSLContext sslContext = new SSLContextBuilder()
            .loadKeyMaterial(keyStore, keyStorePassword.toCharArray(), keyStorePassword.toCharArray())
            .loadTrustMaterial(trustStore, trustStorePassword.toCharArray(), (cert, authType) -> sslTrustStrategy)
            .build();
    HostnameVerifier hostnameVerifier = sslTrustStrategy ? new NoopHostnameVerifier() :
            SSLConnectionSocketFactory.getDefaultHostnameVerifier();
    SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
    HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
    HttpComponentsClientHttpRequestFactory httpComponentsHttpClientFactory =
            new HttpComponentsClientHttpRequestFactory(httpClient);
    RestTemplate restTemplate = new RestTemplate(httpComponentsHttpClientFactory);
    return restTemplate;
}

If sslTrustStrategy = true,

  1. trust all certificates due to (cert, authType) -> sslTrustStrategy
  2. Dont just trust hosts in the certificate but trust all (due to NoopHostnameVerifier, else trust only the hosts in the cerificate)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPrabhu RView Question on Stackoverflow
Solution 1 - SpringDanieleDMView Answer on Stackoverflow
Solution 2 - SpringroubleView Answer on Stackoverflow
Solution 3 - SpringRaghuramView Answer on Stackoverflow
Solution 4 - SpringRan AdlerView Answer on Stackoverflow
Solution 5 - SpringYash JagdaleView Answer on Stackoverflow
Solution 6 - SpringAmit ParasharView Answer on Stackoverflow
Solution 7 - Springuser1986251View Answer on Stackoverflow
Solution 8 - SpringSérgio Thiago MendonçaView Answer on Stackoverflow
Solution 9 - SpringsagarisView Answer on Stackoverflow
Solution 10 - SpringOleg MaksymukView Answer on Stackoverflow
Solution 11 - SpringSatsView Answer on Stackoverflow
Solution 12 - SpringMaksView Answer on Stackoverflow
Solution 13 - SpringR. AhmadiView Answer on Stackoverflow
Solution 14 - Springabhihello123View Answer on Stackoverflow