7

I use RestTemplate config like this :

private RestTemplate createRestTemplate() throws Exception {
        final String username = "admin";
        final String password = "admin";
        final String proxyUrl = "localhost";
        final int port = 443;

        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(proxyUrl, port),
                new UsernamePasswordCredentials(username, password));

        HttpHost host = new HttpHost(proxyUrl, port, "https");

        HttpClientBuilder clientBuilder = HttpClientBuilder.create();

        clientBuilder.setProxy(host).setDefaultCredentialsProvider(credsProvider).disableCookieManagement();

        HttpClient httpClient = clientBuilder.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);

        return new RestTemplate(factory);
    }

And the this is how my method work:

public String receiveMessage(String message) {
        try {
            restTemplate = createRestTemplate();
            ObjectMapper mapper = new ObjectMapper();
            Class1 class1 = null;
            String json2 = "";

            class1= mapper.readValue(message, Class1.class);

            Class1 class2 = restTemplate.getForObject(URL_SERVICE_1 + "/class1/findByName?name=" + class1.getName(),
                    Class1.class);
            System.out.println("Server 1 : " + message);
            json2 = mapper.writeValueAsString(class2);

            return "Error - " + json2;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            return e.getMessage();
        }

    }

URL_SERVICE_1 contains https://localhost

When I tried to call function GET, I always get return like this :

I/O error on GET request for "https://localhost/class1/findByName?name=20-1P": Host name 'localhost' does not match the certificate subject provided by the peer (CN=*.webku-cool.com, OU=EssentialSSL Wildcard, OU=Domain Control Validated); nested exception is javax.net.ssl.SSLPeerUnverifiedException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=*.webku-cool.com, OU=EssentialSSL Wildcard, OU=Domain Control Validated)

I don't know the correct setting for restTemplate with https. I already tried 23 references about SSL Settings and got same error.

1. Reference

2. Reference

3. Reference

Community
  • 1
  • 1
David Vincent
  • 634
  • 1
  • 8
  • 33

4 Answers4

9

As accepted answer has deprecated code, this is what I found helpful:

SSLContextBuilder sslcontext = new SSLContextBuilder();
            sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            httpclient = HttpAsyncClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build();
Dudi
  • 2,340
  • 1
  • 24
  • 39
6

The correct solution for this problem is to correct the ssl certificate by adding localhost to the list of subjects. However, if your intent is to bypass ssl for development purpose, you would need to define a connection factory which always returns the result of hostname verification as true.

SSLClientHttpRequestFactory

public class SSLClientHttpRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
        try {
            if (!(connection instanceof HttpsURLConnection)) {
                throw new RuntimeException("An instance of HttpsURLConnection is expected");
            }

            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;

            TrustManager[] trustAllCerts = 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) {
                }

            } };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));

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

            super.prepareConnection(httpsConnection, httpMethod);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
     * see
     * http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566
     * -2342133.html (Java 8 section)
     */
    private static class MyCustomSSLSocketFactory extends SSLSocketFactory {

        private final SSLSocketFactory delegate;

        public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
            this.delegate = delegate;
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        @Override
        public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose)
                throws IOException {
            final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final String host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                final int localPort) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final InetAddress host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                final int localPort) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }

        private Socket overrideProtocol(final Socket socket) {
            if (!(socket instanceof SSLSocket)) {
                throw new RuntimeException("An instance of SSLSocket is expected");
            }
            ((SSLSocket) socket).setEnabledProtocols(new String[] { "TLSv1" });
            return socket;
        }
    }
}

And use the above mentioned connection factory as the constructor argument for RestTemplate. The part of the code which overrides the host name verification to always return true is as follows:

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

Happy coding!

ritesh.garg
  • 3,725
  • 1
  • 15
  • 14
  • You can't get a cert for `localhost` from a public CA (including Comodo) after 1 Nov 2015. Depending on the webserver, another possibility is to use the/a correct name in the URL, perhaps `test.webku-cool.com` or perhaps a value in SAN which is not shown in the Q, and set your system's name resolution (typically hosts file or local/proxy DNS, but maybe other) to map that name to 127.0.0.1. – dave_thompson_085 Jun 19 '16 at 16:35
1

Here is how I made it to work: 1. This bean ignores SSL check 2. It also ignores certificate mismatch

@Bean
    public RestTemplate restTemplate()
            throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

        SSLContextBuilder sslcontext = new SSLContextBuilder();
        sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());

        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                                                               .loadTrustMaterial(null, acceptingTrustStrategy)
                                                               .build();

        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);

        CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(
                NoopHostnameVerifier.INSTANCE)
                                                    .build();

        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();

        requestFactory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }
DecipherX
  • 36
  • 1
  • 3
  • Thanks, This solution works if SSL to be ignored for localhost during development or to be called by another application which resides in same host. – Anand May 19 '23 at 11:28
0

This option worked for me after trying lot of different options from online... Thanks a lot ...

SSLContextBuilder sslcontext = new SSLContextBuilder();
            sslcontext.loadTrustMaterial(null, new TrustSelfSignedStrategy());
HttpClient httpClient = HttpAsyncClients.custom().setSSLContext(sslcontext.build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
Raj
  • 1