In Spring RestTemplate, when connecting to an HTTPS endpoint with a self-signed certificate, we would need to configure the TrustStore to get the response properly
Self-signed certificates are not issued by known Certificate Authorities (CA) but rather by the server hosting the certificate
TrustStore in Java is used to store certificates of thrid parties
The following example sends a GET request to self-signed.badssl.com
with a normal RestTemplate
restTemplate.getForEntity("https://self-signed.badssl.com/", String.class, Collections.emptyMap());
Then the SSLHandshakeException response is expected output
javax.net.ssl.SSLHandshakeException: PKIX path building failed
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This tutorial walks you through the steps of connecting to a self-signed cert URL in Spring RestTemplate. We use self-signed.badssl.com
as the example server endpoint
Get the self-signed cert
You may download the self-signed cert by using either your browser or the openssl
command-line tool
The below is using openssl
to download the cert and output to the cert file badssl-com.pem
echo quit\
| openssl s_client -servername self-signed.badssl.com -showcerts -connect self-signed.badssl.com:443\
| openssl x509 -outform PEM\
> badssl-com.pem
Convert pem to p12 file
Java supports 2 file formats jks and p12 (default since Java 9) for storing keys and certificates
You may use keytool
to convert the pem file to p12 file. keytool
is a command-line utility shipped by default with JRE/JDK
keytool -import -keystore badssl-com.p12 -alias badssl-com -file badssl-com.pem -trustcacerts
keytool
will ask you to enter the password for badssl-com.p12 and if you trust the cert
Enter keystore password: changeit
Re-enter new password: changeit
Trust this certificate? [no]: yes
Configure TrustStore
Copy the badssl-com.p12
file to resources folder
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── demo
│ │ │ └── DemoApplication.java
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── badssl-com.p12
Spring RestTemplate is a wrapper of multiple HTTP client instances such as the default URLConnection or Apache HTTPClient. In this example, we configure the TrustStore with Apache HttpClient, the dependency can be included in the pom.xml as below
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
We use loadTrustMaterial(URL url, char[] storePassword) method of SSLContextBuilder class to configure the trust store in RestTemplate
@Bean
public RestTemplate restTemplateWithTrustStore(RestTemplateBuilder builder) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(trustStore.getURL(), trustStorePassword.toCharArray())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
return builder
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(httpClient))
.build();
}
The trustStore
and trustStorePassword
are settings loaded from application.properties and @Value binding
trust-store=classpath:badssl-com.p12
trust-store-password=changeit
@Value("${trust-store}")
private Resource trustStore;
@Value("${trust-store-password}")
private String trustStorePassword;
Testing
Now we execute the GET request again with the above restTemplateWithTrustStore. The response status should be 200
@Autowired private RestTemplate restTemplateWithTrustStore;
@Test
public void okResponse() throws Exception {
ResponseEntity<String> response = restTemplateWithTrustStore
.getForEntity("https://self-signed.badssl.com/", String.class, Collections.emptyMap());
assertEquals(HttpStatus.OK, response.getStatusCode());
}
Conclusion
In this tutorial, we learned how to get the self-signed cert, import it into TrustStore and configure Spring RestTemplate to execute HTTPS requests to self-signed APIs