I am using Java 17 Spring Boot configured to use Jetty running as an mTLS microservice.
I would like to log failed connections (due to misaligned keys or client keys not recognised in the CA -- all of which happens during the SSL handshaking).
I would like this to use a custom error/log handler and not the standard Error Logging..
Does anyone have some code that does this?
Thanks in advance :)
Thanks for your help and apologies for the rather vague question, but here is the solution.
The problem was that mTLS connection issues are outside of the usual Spring event handling and hence they won't show up when there is a failed connection.
Below is a working example, showing the addition of a Jetty specific Event Listener:
@Slf4j
@Configuration
public class MTLSConfig {
@Bean
public WebServerFactoryCustomizer<JettyServletWebServerFactory> masslSecurityConfigurer(
@Value("${app.mtls.enable}") Boolean enableMTLS,
@Value("${app.mtls.port-number}") Integer portNumber,
KeyManager[] mtlsKeyManager, // This is loaded from an in-memory KeyStore as a @Bean
TrustManager[] mtlsTrustManager
) {
return factory -> factory.addServerCustomizers(server -> {
try {
if (!enableMTLS) {
log.warn("⚠️ This server will NOT be secured by mTLS ⚠️");
HttpConfiguration httpConfig = new HttpConfiguration();
ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
httpConnector.setPort(portNumber);
server.addConnector(httpConnector);
log.debug("Done -- plain, unsecured access is provided via Port: {}", portNumber);
return;
}
log.debug("About to build an mTLS secured service for all requests..");
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(mtlsKeyManager, matlsTrustManager, new SecureRandom());
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setSslContext(sslContext);
sslContextFactory.setNeedClientAuth(true); // Turn on mTLS
sslContextFactory.setSniRequired(false);
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, "http/1.1");
sslConnectionFactory.setEventListeners(Set.of(new LoggingSslHandshakeListener()));
ServerConnector sslConnector = new ServerConnector(
server,
sslConnectionFactory,
new HttpConnectionFactory(https)
);
sslConnector.setPort(portNumber);
server.setConnectors(new Connector[]{sslConnector});
log.debug("Done -- mTLS secured access via Port: {}.", portNumber);
} catch (Exception e) {
throw new IllegalStateException(
"Failed to configure mTLS", e);
}
});
}
This is then the event listener code:
public class LoggingSslHandshakeListener implements SslHandshakeListener {
@Override
public void handshakeSucceeded(Event event) {
// Successful connection! (don't actually need this)
}
@Override
public void handshakeFailed(Event event, Throwable failure) {
// Unsuccessful connection.. (TODO -- add in custom logging)
}
}
So when it fails you can report this to DevOps, using the Throwable, i.e.:
javax.net.ssl.SSLHandshakeException
: 'Received fatal alert: unknown_ca'