java—以编程方式使用自定义sslcontext配置spring引导(对于MTL)

l7mqbcuq  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(466)

问题

以编程方式配置spring引导以使用我的自定义 SSLContext . 用于MTL。

上下文

spring的文档只提供了一种清晰的方式来配置ssl(通过 application.properties ):

server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.trust-store=classpath:truststore.jks
...

然而,这个解决方案缺乏深度,因为在某些场景中,我想利用定制自己的解决方案 SSLContext . 例如,将mtls配置为不仅信任通过 keytool ,但同时信任我的自签名证书和放置在java默认信任库中的证书( lib/security/cacerts ).
当然,我可以使用前面提到的 keytool ,但我正在寻找更灵活的方法,因此提供了我自己的方法 SSLContext .
spring提供了一个关于配置web服务器的部分,其中说使用 TomcatServletWebServerFactory 或者 ConfigurableServletWebServerFactory ,但它们并没有真正深入。
我试着创造一个 Component :

@Component
public class CustomServletCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    private static final String SERVER_CERTIFICATE_PATH = "identity.jks";
    private static final char[] PASSWORD = "secret".toCharArray();

    private static final String CLIENT_CERTIFICATE_PATH = "certs/client.cer";

    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        factory.setSslStoreProvider(new SslStoreProvider() {
            @Override
            public KeyStore getKeyStore() throws Exception {
                var certificateAsInputStream = this.getClass().getClassLoader().getResourceAsStream(SERVER_CERTIFICATE_PATH);
                var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(certificateAsInputStream, PASSWORD);

                return keyStore;
            }

            @Override
            public KeyStore getTrustStore() throws Exception {
                var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(null);
                var organisationRootCertBytes = this.getClass().getClassLoader().getResourceAsStream(CLIENT_CERTIFICATE_PATH).readAllBytes();
                var certificateFactory = CertificateFactory.getInstance("X.509");
                var certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(organisationRootCertBytes));
                keyStore.setCertificateEntry("server", certificate);

                return keyStore;
            }
        });
    }
}

但无济于事。

uhry853o

uhry853o1#

不幸的是,这在spring boot+tomcat中是不可能的。它没有注入sslcontext或其他属性(如sslserversocketfactory、trustmanager或keymanager)的选项。
但是,如果您仍然想使用springboot并想对其进行完全配置,如果您不关心springboot使用的是哪种服务器,我建议您使用jetty。
下面是如何使用spring boot+jetty实现这一点的基本实现:

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;

import java.util.Collections;

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    public SslContextFactory.Server sslContextFactory() {
        SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
        sslContextFactory.setSslContext(sslContext);
        sslContextFactory.setIncludeProtocols(protocols);
        sslContextFactory.setIncludeCipherSuites(ciphers);
        sslContextFactory.setNeedClientAuth(true);
        return sslContextFactory;
    }

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory(SslContextFactory.Server sslContextFactory) {
        JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
        factory.setPort(8443);

        JettyServerCustomizer jettyServerCustomizer = server -> server.setConnectors(new Connector[]{new ServerConnector(server, sslContextFactory)});
        factory.setServerCustomizers(Collections.singletonList(jettyServerCustomizer));
        return factory;
    }

}

你还需要告诉spring不要再使用tomcat了,改用jetty。您可以通过将以下代码段添加到pom中来实现这一点:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

相关问题