I'm building a Spring WebClient which internally calls to REST API's which are hosted in different server. To do that I need to send public key (.cert) and private key (.key) to every request for the handshake. I'm not sure how to do that with Spring WebClient.
I tried setting up WebClient, but struck at adding this peace of code
WebClient Builder
this.webCLient = WebClient.builder()
.baseUrl("https://some-rest-api.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString())
.build();
Actual Call
this.webClient.get()
.uri("/getData")
.exchange()
.flatMap(clientResponse -> {
System.out.println(clientResponse);
return clientResponse.bodyToMono(MyClass.class);
});
Since there were no certificates added to the request, I'm getting the handshake error on the log
javax.net.ssl.SSLException: Received fatal alert: handshake_failure
How to add those certificates to the WebClient requests, so I don't get this error ? I have the certificates, but not sure how to add it.
It took me some time to find the missing piece in Thomas' answer.
Here it is:
public static SslContext getTwoWaySslContext() {
try(FileInputStream keyStoreFileInputStream = new FileInputStream(ResourceUtils.getFile(clientSslKeyStoreClassPath));
FileInputStream trustStoreFileInputStream = new FileInputStream(ResourceUtils.getFile(clientSslTrustStoreClassPath));
) {
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(keyStoreFileInputStream, clientSslKeyStorePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, clientSslKeyStorePassword.toCharArray());
KeyStore trustStore = KeyStore.getInstance("jks");
trustStore.load(trustStoreFileInputStream, clientSslTrustStorePassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(trustStore);
return SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build();
} catch (Exception e) {
log.error("An error has occurred: ", e);
}
return null;
}
HttpClient httpClient = HttpClient.create().secure(sslSpec -> sslSpec.sslContext(SslUtil.getTwoWaySslContext()));
ClientHttpConnector clientHttpConnector = new ReactorClientHttpConnector(httpClient);
WebClient webClient = webClientBuilder
.clientConnector(clientHttpConnector)
.baseUrl(baseUrl)
.build();
Enjoy!
taken from the documentation Spring Webclient - Reactor Netty
To access the ssl configurations you need to supply a custom netty HttpClient with a custom sslContext.
SslContext sslContext = SslContextBuilder
.forClient()
// build your ssl context here
.build();
HttpClient httpClient = HttpClient.create().secure(sslSpec -> sslSpec.sslContext(sslContext));
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With