26

I am trying to send a request to following address. The certificate is not valid and I would like to ignore it. I wrote following code based on my research on 1, 2 but I am not able to complete it. I am using Java 1.7,

https://api.stubhubsandbox.com/search/catalog/events/v3

Code

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 void checkClientTrusted(
                java.security.cert.X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub

        }
        public void checkServerTrusted(
                java.security.cert.X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub

        }
    }
};

public static void main(String[] args) {
    TrustStrategy acceptingTrustStrategy = 

    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);
    String url = "https://api.stubhubsandbox.com/search/catalog/events/v3";
    RestTemplate rest = new RestTemplate();
    Map<String, String> mvm = new HashMap<String, String>();
    mvm.put("Authorization", "Bearer TOKEEEEEEEN");
    Object object = rest.postForObject(url, null, Object.class, mvm);
    System.err.println("done");


}
Community
  • 1
  • 1
Daniel Newtown
  • 2,873
  • 8
  • 30
  • 64
  • I miss setting `UNQUESTIONING_TRUST_MANAGER` to `SSLContext` in your code. – Michal Foksa Apr 17 '16 at 07:21
  • @MichalFoksa how to set that? Also I have jdk 1.7 but part of my code is 1.8 not sure how to fix it. – Daniel Newtown Apr 17 '16 at 08:19
  • 1
    You are forcing a `RestTemplate` instance to accept self-signed certificates at `RestTemplate restTemplate = new RestTemplate(requestFactory);`. But then you have `RestTemplate rest = new RestTemplate(); rest.postForObject(url, null, Object.class, mvm);`. This means that the actual REST call uses a `RestTemplate` instance that does not accept self-signed certificate. If you use `restTemplate.postForObject` instead, your call will go through. – manish Apr 22 '16 at 09:32

8 Answers8

23

As you may have noticed, Spring's RestTemplate delegates all the HTTP(S) related stuff to the underlying implementation of ClientHttpRequestFactory. Since you're using the HttpClient-based implementation, here are a couple of useful SO links on how to achieve this for the internal HttpClient:

Apparently, since version 4.4, this can be done as:

CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
Community
  • 1
  • 1
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • Thanks for your answer, is not it possible to use restTemplate at all? I've already tried proposed solution of your second bullet point but could not make it work for JDK 1.7 – Daniel Newtown Apr 19 '16 at 12:02
  • 1
    RestTemplate is just a wrapper over a `ClientHttpRequestFactory`. You seem to be using the `HttpClient`-based implementation already, so all you have to do is change the way you build your internal HttpClient. – Costi Ciudatu Apr 19 '16 at 12:25
  • 2
    The above code did not work for me. Same error occured. The code [in this blog post](https://memorynotfound.com/ignore-certificate-errors-apache-httpclient/) did – Nom1fan Sep 04 '18 at 10:41
  • 4
    Worked for me, connect the dots from httpClient to restTemplate like this: `CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); RestTemplate restTemplate = new RestTemplate(factory);` – Alex K. Feb 04 '19 at 17:02
20

To bypass SSL checks in several spring projects I always re-use a SSLUtils class I wrote (or found) some time ago in conjunction with spring's RestTemplate. Using the class provided below you just need to call the static SSLUtil.turnOffSslChecking() method before you send your request.

import javax.net.ssl.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public final class SSLUtil{

    static {
        //for localhost testing only
        javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
        new javax.net.ssl.HostnameVerifier(){

            public boolean verify(String hostname,
                    javax.net.ssl.SSLSession sslSession) {
                if (hostname.equals("localhost")) {
                    return true;
                }
                return false;
            }
        });
    }

    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.");
    }
}

Give it a try. Hope this works and turns out as an easy solution for you.

mika
  • 2,495
  • 22
  • 30
  • Thanks for that - I can vouch that your code for disabling the host name checking works. It is worth pointing out that this only works when using the default RestTemplate that uses the basic Java HttpURLConnection HTTP library. For the more common case of using Apache HttpComponents it is quite a bit more complicated. I ended up creating a 'local' profile that used a basic RestTemplate with security disabled, and a RestTemplate with Apache HttpComponents with full security for all other profiles – Patrick Herrera Sep 19 '16 at 08:09
  • Awesome!! After spending days of Unsucessfull attempts, This one worked like charm without a glitch. Thanks for the Wonderful answer – Avinash Mar 29 '19 at 15:14
  • 1
    Works in Spring-Boot version 2.1.6.RELEASE with spring-web v 5.1.8 in a project using the default org.springframework.http.client classes. All other solutions seem to require switching to Apache HTTP Client. – chrisinmtown Oct 08 '19 at 15:23
  • Thanks @mika for the code I found the turnOn() method was incomplete and posted a slightly improved version at https://stackoverflow.com/questions/23504819/how-to-disable-ssl-certificate-checking-with-spring-resttemplate/58291331#58291331 – chrisinmtown Oct 08 '19 at 18:12
9

Add the SSLContext and X509TrustManager and the HostnameVerifier instances to the http ClientBuilders. They can be for instance (given my example)

  1. HttpClientBuilder with HttpComponentsClientHttpRequestFactory
  2. OkHttpClient.Builder with OkHttp3ClientHttpRequestFactory

Here's the sample code for Apache HttpClient & OkHttpClient. Its for demo purpose but you can use it

Apache HttpClient

RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.HttpClient));

and OkHttpClient

RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.OkHttpClient));

The SSLClientFactory is custom class here

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

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

import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;

import okhttp3.OkHttpClient;

public abstract class SSLClientFactory {

    private static boolean allowUntrusted = false;
    private static final long LOGIN_TIMEOUT_SEC = 10;
    private static HttpClientBuilder closeableClientBuilder = null;
    private static OkHttpClient.Builder okHttpClientBuilder = null;

    public enum HttpClientType{
        HttpClient,
        OkHttpClient
    } 


    public static synchronized ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientType httpClientType){

        ClientHttpRequestFactory requestFactory = null;

        SSLContext sslContext = SSLClientFactory.getSSlContext();

        if(null == sslContext){
            return requestFactory;
        }

        switch (httpClientType) {

        case HttpClient:
            closeableClientBuilder = HttpClientBuilder.create();

            //Add the SSLContext and trustmanager
            closeableClientBuilder.setSSLContext(getSSlContext());
            //add the hostname verifier
            closeableClientBuilder.setSSLHostnameVerifier(gethostnameVerifier());   

            requestFactory = new HttpComponentsClientHttpRequestFactory(closeableClientBuilder.build());

            break;
        case OkHttpClient:
            okHttpClientBuilder = new OkHttpClient().newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);

            //Add the SSLContext and trustmanager
            okHttpClientBuilder.sslSocketFactory(getSSlContext().getSocketFactory(), getTrustManager());
            //add the hostname verifier
            okHttpClientBuilder.hostnameVerifier( gethostnameVerifier());

            requestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClientBuilder.build());

            break;
        default:
            break;
        }

        return requestFactory;

    }


    private static SSLContext getSSlContext(){



        final TrustManager[] trustAllCerts = new TrustManager[]{getTrustManager()};

        SSLContext sslContext = null;
        try {

            sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }



        return sslContext;

    }

    private static X509TrustManager getTrustManager(){

        final X509TrustManager trustManager = new X509TrustManager() {

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                X509Certificate[] cArrr = new X509Certificate[0];
                return cArrr;
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // TODO Auto-generated method stub

            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // TODO Auto-generated method stub

            }
        };

        return trustManager;
    }

    private static HostnameVerifier gethostnameVerifier(){

        HostnameVerifier hostnameVerifier = new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        };

        return hostnameVerifier;

    }

}
Novice
  • 557
  • 1
  • 7
  • 16
7

Not sure if things have changed after jdk6, but last time I was trying to do this we needed to import the SSL certificate to the keystore of the JAVA_HOME used to run the programs utilizing the trusted ssl.

First, you will need to export the certificate to a file. In windows, you can use any browser to save the SSL certificate to your personal certificates store and then run mmc, add certificates snapin (File/Add Remove Snapin) and save the certificate to disk.

Then you need to import the certificate to trusted domain cacerts using the keytool. But you need to import it to the keystore that your java_home uses when running your programs above.

The command below will add certificate file "mycertificate.cer" to keystore in file "cacerts.jks". The alias is "webservice" :

"%JAVA_HOME%\bin\keytool" -import -trustcacerts -alias webservice -file mycertificate.cer -keystore cacerts.jks

Usually, the Keystore password is "changeit", no quotes. Change it for production use

chrisl08
  • 1,658
  • 1
  • 15
  • 24
  • Thanks for your answer, I know might need to download the certificate but I was just wondering if it is possible to ignore the certificate in the first place. – Daniel Newtown Apr 17 '16 at 05:27
2

If you are using Apache httpClient 4.5 following:

public static void main(String... args)  {

    try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) {
        HttpGet httpget = new HttpGet("https://example.com");
        System.out.println("Executing request " + httpget.getRequestLine());

        httpclient.execute(httpget);
        System.out.println("----------------------------------------");
    } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
        throw new RuntimeException(e);
    }
}

private static CloseableHttpClient createAcceptSelfSignedCertificateClient()
        throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

    // use the TrustSelfSignedStrategy to allow Self Signed Certificates
    SSLContext sslContext = SSLContextBuilder
            .create()
            .loadTrustMaterial(new TrustSelfSignedStrategy())
            .build();

    // we can optionally disable hostname verification. 
    // if you don't want to further weaken the security, you don't have to include this.
    HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

    // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
    // and allow all hosts verifier.
    SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

    // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
    return HttpClients
            .custom()
            .setSSLSocketFactory(connectionFactory)
            .build();
}
Brijesh Patel
  • 417
  • 5
  • 11
2
 @Bean
       public RestTemplate getRestTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
            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);
          return new RestTemplate(requestFactory);
       }

This code bypasses the certificate validation and you can connect with an insecure way by accepting all hosts and certificates. This code works for me

UDIT JOSHI
  • 1,298
  • 12
  • 26
1

You can use this code:

    @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;
}

in java 7 replace lambda expression with:

        TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        @Override public boolean isTrusted(X509Certificate[] x509Certificates, String s)
                        throws CertificateException {
            return true;
        }
    };
DanieleDM
  • 1,762
  • 2
  • 16
  • 13
  • Related site: https://www.javacodegeeks.com/2016/02/skip-ssl-certificate-verification-spring-rest-template.html – voodoo98 Sep 20 '19 at 14:09
1

SSLUtils solution posted by @Sebastián Ezquerro is spot on. I tested this both with RestTemplate and FeignClient - works like a champ. Many thanks to all contributors. In case, you are wondering Feign client solution, here it is:

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        BasicAuthRequestInterceptor auth = new BasicAuthRequestInterceptor(username,  password);
        RequestTemplate template = new RequestTemplate();
        template.header(HttpHeaders.ACCEPT, "application/json");
        template.header(HttpHeaders.CONTENT_TYPE, "application/json");
        auth.apply(template);

       // disable SSL self signed certificate check
       try {
           SSLUtil.turnOffSslChecking();
        } catch (NoSuchAlgorithmException e) {
           log.error("Error disabling SSL check", e);
        } catch (KeyManagementException e) {
          log.error("Error disabling SSL check", e);
        }
        return auth;
    }
DanielM
  • 3,598
  • 5
  • 37
  • 53