Spring Boot 2: How to enable two-way SSL with embedded Tomcat

In Spring Boot 2, the configuration classes of embedded webservers (like Tomcat) have slightly changed.

Below is a way to enable a two-way SSL connector on Tomcat.

Versions used:

  • Spring Boot 2.0.4.RELEASE
  • Embedded Tomcat version: 8.5.32
package re.vianneyfaiv.twowayssl;

import org.apache.catalina.connector.Connector;
import org.apache.commons.lang3.StringUtils;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.nio.file.Paths;

@Configuration
public class TomcatWithTwoWaySslConfig {

    @Autowired
    private ServerProperties serverProperties;

    private int port = 9090;

    private String keystoreFile = "/absolute/path/to/keystore";
    private String keystorePassword = "keystore-password";

    private String truststoreFile = "/absolute/path/to/truststore";
    private String truststorePassword = "truststore-password";

    @Bean
    public TomcatServletWebServerFactory servletContainer() {

        // Creates default Spring Boot Tomcat config with default HTTP(s) Connector based on ServerProperties (server.* props)
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(serverProperties.getPort());

        // Defines application context path (if set)
        if(StringUtils.isNotBlank(serverProperties.getServlet().getContextPath())) {
            tomcat.setContextPath(serverProperties.getServlet().getContextPath());
        }

        // Creation of a new HTTPS connector
        tomcat.addAdditionalTomcatConnectors(twoWaySSL(port, keystoreFile, keystorePassword, truststoreFile, truststorePassword));

        return tomcat;
    }

    private static Connector twoWaySSL(int port,
                                       String keystoreFile, String keystorePassword,
                                       String truststoreFile, String truststorePassword) {

        // Create HTTP connector
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setPort(port);
        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();

        // Enable SSL
        connector.setScheme("https");
        connector.setSecure(true);
        protocol.setSSLEnabled(true);

        // Keystore config
        File keystore = Paths.get(keystoreFile).toFile();
        protocol.setKeystoreFile(keystore.getAbsolutePath());
        protocol.setKeystorePass(keystorePassword);

        // Truststore config
        File truststore = Paths.get(truststoreFile).toFile();
        protocol.setTruststoreFile(truststore.getAbsolutePath());
        protocol.setTruststorePass(truststorePassword);

        // Enable two way SSL
        protocol.setClientAuth(SSLHostConfig.CertificateVerification.REQUIRED.name());
        protocol.setSSLVerifyClient(SSLHostConfig.CertificateVerification.REQUIRED.name());

        return connector;
    }
}

Let me know if that does not work for you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.