I have currently implemented mutual TLS in my Spring Boot application and I am doing it programmatically, like so:
@Bean
public ServletWebServerFactory servContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
TomcatConnectorCustomizer tomcatConnectorCustomizer = new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setPort(8443);
connector.setScheme("https");
connector.setSecure(true);
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setSSLEnabled(true);
protocol.setKeystoreType("PKCS12");
protocol.setKeystoreFile(keystorePath);
protocol.setKeystorePass(keystorePass);
//client must be authenticated (the cert he sends should be in our trust store)
protocol.setSSLVerifyClient(Boolean.toString(true));
protocol.setTruststoreFile(truststorePath);
protocol.setTruststorePass(truststorePass);
protocol.setKeyAlias("APP");
}
};
tomcat.addConnectorCustomizers(tomcatConnectorCustomizer);
return tomcat;
}
This is working fine and as expected, but I have a requirement where I need to update the trust store during runtime (for example, when a @getmapping
endpoint is invoked).
Specifically, I need to add a new certificate to the TrustStore without stopping/restarting the application. So I will have to somehow modify the in-memory trust store of my application.
How can I do this?
I tried to add a bean dynamically which adds a new Trust Manager to the SslContext, but this does not work.
@GetMapping("/register")
public String Register() throws Exception {
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) appContext;
ConfigurableListableBeanFactory beanRegistry = configContext.getBeanFactory();
SSLContext sslContext = getSSLContext();
beanRegistry.registerSingleton("sslContext", sslContext);
return "okay";
}
public SSLContext getSSLContext() throws Exception {
TrustManager[] trustManagers = new TrustManager[] {
new ReloadableX509TrustManager(truststoreNewPath)
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
SSLContext.setDefault(sslContext);
return sslContext;
}
I also tried to invoke the above getSSLContext()
as a @bean, which did not work either.
My current solutions are based on these links, which are for Java, but I'm not sure how to implement them in my Spring application.
I have found a solution which describes exactly how to have a dynamic trust store, but I am not able to figure out how to reload the trust store during runtime. Say, for example, when a GET endpoint is invoked.
Client Certificate authentication without local truststore
I have a list of Certificates, I just need to know how to invoke the ReloadableX509TrustManager
's addCertificates()
method.
ReloadableX509TrustManager
is perfect candidate to become a bean and use it to create context like above – Hyoscyamine