Reputation: 14222
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
Upvotes: 142
Views: 325421
Reputation: 1873
@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;
}
And if you use custom HttpClientConnectionManager, it will override the builder direct configuration:
https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/main/java/org/apache/http/impl/client/HttpClientBuilder.java#L316
You may need create ConnectionManager with custom socketFactoryRegistry:
https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/main/java/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java#L130
Upvotes: 115
Reputation: 331
I also faced similar issues on Spring boot Version 3.1.1, here is the solution that worked for me to skip SSL validation. Hopefully this should work for others who are using spring boot 3 and httpclient5
check the full configuration code here...
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestClientConfiguration {
@Primary
@Bean("restClient")
public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
final var restTemplate = new RestTemplate();
ClientHttpRequestFactory requestFactory = disableSSlHttpClient5();
restTemplate.setRequestFactory(requestFactory);
return restTemplate;
}
private HttpComponentsClientHttpRequestFactory disableSSlHttpClient5()
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial((X509Certificate[] certificateChain, String authType) -> true) // <--- accepts each certificate
.build();
Registry<ConnectionSocketFactory> socketRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(URIScheme.HTTPS.getId(), new SSLConnectionSocketFactory(sslContext))
.register(URIScheme.HTTP.getId(), new PlainConnectionSocketFactory())
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(new PoolingHttpClientConnectionManager(socketRegistry))
.setConnectionManagerShared(true)
.build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
}
Upvotes: 5
Reputation: 3056
Here is the answer for Spring 3.1.2
Dependency
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
Code
@Bean
public RestTemplate getRestTemplate() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
TrustStrategy acceptingTrustStrategy = (x509Certificates, s) -> true;
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create().setSSLSocketFactory(csf).build();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
Imports
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.ssl.TrustStrategy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
Upvotes: -1
Reputation: 491
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
Not a right way how problem can be solved
import SSL certificate to Java cacerts (certificate storage)
keytool -importcert -trustcacerts -noprompt -storepass changeit -alias name -keystore "C:\Program Files\Java\jdk-11.0.2\lib\security\cacerts" -file file.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();
}
Upvotes: 3
Reputation: 1508
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;
Upvotes: 18
Reputation: 1297
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();
Upvotes: 24
Reputation: 52645
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.
Upvotes: 45
Reputation: 1728
@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,
Upvotes: 1
Reputation: 18191
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;
}
Upvotes: 91
Reputation: 2955
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.
Upvotes: 1
Reputation: 1
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())
}
Upvotes: 0
Reputation: 67
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);
}
});
Upvotes: 5
Reputation: 3711
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;
}
}
Upvotes: 11
Reputation: 115
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()
);*
Upvotes: 1
Reputation: 31
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!
Upvotes: 3
Reputation: 1457
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);
}
Upvotes: 7