It is not intuitive that there is some work to do to get WebClient to communicate with certs. Having written this twice now across two projects, here it is:
// Pull these in however you like
@Value("${user.keystore}")
String keyStoreLocation;
@Value("${user.keystore.passwd}")
String keyStorePassword;
@Value("${user.truststore}")
String trustStoreLocation;
@Value("${user.truststore.passwd}")
String trustStorePassword;
...
HttpClient httpClient = HttpClient.create().secure(spec ->
{
try {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStoreLocation)), keyStorePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream((ResourceUtils.getFile(trustStoreLocation))), trustStorePassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
spec.sslContext(SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build());
} catch (Exception e) {
logger.error("Unable to set SSL Context", e);
}
});
WebClient webClient = WebClient.builder()
.baseUrl(baseUrl)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
Given a key and truststore, build an ssl context inside an httpClient, and pass that to your WebClient.
Apparently you can also do this with JVM options:
-Djavax.net.ssl.keyStore=<path>/keystore.jks
-Djavax.net.ssl.keyStorePassword=<password>
-Djavax.net.ssl.trustStore=<path>/truststore.ts
-Djavax.net.ssl.trustStorePassword=<password>
-Djavax.net.ssl.trustStoreType=JKS
-Dio.netty.handler.ssl.noOpenSsl=true
I have not personally tried this.
Now you don't have to go dig through forum threads and github tickets.