Does Spring Boot support Server Name Indication (SNI)?

岁酱吖の 提交于 2020-03-23 12:01:22

问题


Does Spring Boot support Server Name Indication (SNI)? Specifically, is it possible for a Spring Boot (2.2.2.RELEASE) application running an embedded Tomcat server and packaged as an executable jar file to support multiple SSL certificates/domains based on the hostname of the incoming request?

It appears Tomcat supports SNI (as of Tomcat 8.5), but I'm not sure how to implement SNI in my Spring Boot app.


回答1:


I was able to verify that Spring Boot running an embedded Tomcat server supports Server Name Indication (SNI) using the following config:

application.properties

abc.com.key-store=${user.dir}/abc.com.p12
xyz.com.key-store=${user.dir}/xyz.com.p12

ApplicationConfig.java

import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class ApplicationConfig {

    @Autowired
    private Environment env;

    @Bean
    public ServletWebServerFactory servletContainer() throws Exception {

        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            // Override TomcatServletWebServerFactory methods (if needed)
        };

        // add SSL Connector
        tomcat.addAdditionalTomcatConnectors(createSSLConnectorForMultipleHosts());

        return tomcat;
    }


    private Connector createSSLConnectorForMultipleHosts() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");

        /**
         * Tomcat 9.0.x server SSL Connector for multiple hosts
         * 
        <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
                   maxThreads="150" SSLEnabled="true"
                   defaultSSLHostConfigName="*.abc.com">
            <SSLHostConfig hostName="*.abc.com">
                <Certificate certificateKeystoreFile="conf/abc.com.p12"
                             type="RSA" />
            </SSLHostConfig>
            <SSLHostConfig hostName="*.xyz.com">
                <Certificate certificateKeystoreFile="conf/xyz.com.p12"
                             type="RSA" />
            </SSLHostConfig>
        </Connector>
         */

        try {
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setPort(8443);
            connector.setAttribute("SSLEnabled", "true");
            connector.setAttribute("defaultSSLHostConfigName", "*.abc.com");

            // *.abc.com
            SSLHostConfig sslHostConfig = new SSLHostConfig();
            sslHostConfig.setHostName("*.abc.com");

            SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
            sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("abc.com.key-store"));

            sslHostConfig.addCertificate(sslHostConfigCertificate);
            connector.addSslHostConfig(sslHostConfig);

            // *.xyz.com
            sslHostConfig = new SSLHostConfig();
            sslHostConfig.setHostName("*.xyz.com");

            sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, Type.RSA);
            sslHostConfigCertificate.setCertificateKeystoreFile(env.getProperty("xyz.com.key-store"));

            sslHostConfig.addCertificate(sslHostConfigCertificate);
            connector.addSslHostConfig(sslHostConfig);

            return connector;
        }
        catch (Exception ex) {
            throw new IllegalStateException("Exception creating SSL Connector: ", ex);
        }
    }

}



回答2:


Spring supports tomcat connector configuration. I did not run this code but this will give you some idea. You can try something like this:

@Bean
public ServletWebServerFactory servletContainer() throws Exception {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addAdditionalTomcatConnectors(createConnector());
    return tomcat;
}

public Connector createConnector() {
    Connector connector = new Connector("org.apache.coyote.http11.Http11AprProtocol");
    connector.setScheme("https");
    connector.setSecure(true);
    connector.setPort(8443);
    connector.addSslHostConfig(getSSLHostConfig());
    return connector;
}

private SSLHostConfig getSSLHostConfig() {
    SSLHostConfig sslHostConfig = new SSLHostConfig();
    sslHostConfig.setHostName("abc.com");
    sslHostConfig.setCertificateFile("abc.crt");
    sslHostConfig.setCaCertificateFile("xyz.crt");
    return sslHostConfig;
}


来源:https://stackoverflow.com/questions/60514176/does-spring-boot-support-server-name-indication-sni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!