How to disable SSL certificate checking with Spring RestTemplate?

后端 未结 9 1096
余生分开走
余生分开走 2020-11-29 18:11

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 acce

相关标签:
9条回答
  • 2020-11-29 18:42
    @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);
    }
    
    0 讨论(0)
  • 2020-11-29 18:46

    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.

    0 讨论(0)
  • 2020-11-29 18:47

    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);
        }
    }
    
    0 讨论(0)
  • 2020-11-29 18:53

    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.");
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:02

    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);
    
    0 讨论(0)
  • 2020-11-29 19:02

    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.

    0 讨论(0)
提交回复
热议问题