Java 配置Spring Boot';以编程方式使用自定义SSLContext的 问题
以编程方式配置Spring引导以使用我的自定义Java 配置Spring Boot';以编程方式使用自定义SSLContext的 问题,java,spring,spring-boot,sslcontext,mtls,Java,Spring,Spring Boot,Sslcontext,Mtls,以编程方式配置Spring引导以使用我的自定义SSLContext。并用于MTL 上下文 Spring只提供了一种明确的方式来配置SSL(通过application.properties): 然而,这个解决方案缺乏深度,因为在某些情况下,我想利用定制自己的SSLContext的优势。例如,将MTL配置为不仅信任通过keytool生成的单个证书,而且信任我的自签名证书和放置在Java默认信任库中的证书(lib/security/cacerts) 当然,我可以使用前面提到的keytool组合它们,但
SSLContext
。并用于MTL
上下文
Spring只提供了一种明确的方式来配置SSL(通过application.properties
):
然而,这个解决方案缺乏深度,因为在某些情况下,我想利用定制自己的SSLContext
的优势。例如,将MTL配置为不仅信任通过keytool
生成的单个证书,而且信任我的自签名证书和放置在Java默认信任库中的证书(lib/security/cacerts
)
当然,我可以使用前面提到的keytool
组合它们,但我正在寻找更灵活的方法,因此提供了我自己的SSLContext
Spring提供了关于的一节,其中说使用类似于TomcatServletWebServerFactory
或ConfigurableServletWebServerFactory
的内容,但它们并没有真正深入
我已尝试创建组件
:
@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;
}
});
}
}
@组件
公共类CustomServletCustomizer实现WebServerFactoryCustomizer{
私有静态最终字符串服务器\u证书\u PATH=“identity.jks”;
私有静态final char[]PASSWORD=“secret”.toCharArray();
私有静态最终字符串CLIENT\u CERTIFICATE\u PATH=“certs/CLIENT.cer”;
@凌驾
public void自定义(ConfigurableServletWebServerFactory){
factory.setSslStoreProvider(新的SslStoreProvider(){
@凌驾
公共密钥库getKeyStore()引发异常{
var certificateAInputStream=this.getClass().getClassLoader().getResourceAsStream(服务器\证书\路径);
var keyStore=keyStore.getInstance(keyStore.getDefaultType());
加载(CertificateAInputStream、密码);
返回密钥库;
}
@凌驾
公共密钥库getTrustStore()引发异常{
var keyStore=keyStore.getInstance(keyStore.getDefaultType());
keyStore.load(null);
var OrganizationRootCertBytes=this.getClass().getClassLoader().getResourceAsStream(客户端证书路径).readAllBytes();
var certificateFactory=certificateFactory.getInstance(“X.509”);
var certificate=certificateFactory.generateCertificate(新的ByteArrayInputStream(OrganizationRootCertBytes));
setCertificateEntry(“服务器”,证书);
返回密钥库;
}
});
}
}
但是没有用。不幸的是,这在Spring Boot+Tomcat中是不可能的。它没有插入SSLContext或其他属性(如SSLServerSocketFactory或TrustManager或KeyManager)的选项 但是,如果您仍然想使用SpringBoot并希望对其进行全面配置,如果您不关心SpringBoot使用的是哪种服务器,我建议您使用Jetty 以下是使用Spring Boot+Jetty实现此功能的基本实现:
import org.eclipse.jetty.server.Connector;
导入org.eclipse.jetty.server.server;
导入org.eclipse.jetty.server.ServerConnector;
导入org.eclipse.jetty.util.ssl.SslContextFactory;
导入org.springframework.boot.SpringApplication;
导入org.springframework.boot.autoconfigure.springboot应用程序;
导入org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
导入org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
导入org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
导入org.springframework.context.annotation.Bean;
导入java.util.Collections;
@SpringBoot应用程序
公共类应用程序{
公共静态void main(字符串[]args){
SpringApplication.run(App.class,args);
}
@豆子
公共SslContextFactory.Server SslContextFactory(){
SslContextFactory.Server SslContextFactory=新的SslContextFactory.Server();
setsslcontextfactory.setSslContext(sslContext);
sslContextFactory.setIncludeProtocols(协议);
sslContextFactory.setIncludecipherSuite(密码);
sslContextFactory.setNeedClientAuth(true);
返回sslContextFactory;
}
@豆子
公共配置ServletWebServerFactory webServerFactory(SslContextFactory.Server SslContextFactory){
JettyServletWebServerFactory=新的JettyServletWebServerFactory();
工厂设置端口(8443);
JettyServerCustomizer JettyServerCustomizer=server->server.setConnectors(新连接器[]{new ServerConnector(服务器,sslContextFactory)});
setServerCustomizer(Collections.singletonList(jettyServerCustomizer));
返回工厂;
}
}
您还需要告诉spring不再使用tomcat,并切换到jetty。您可以通过将以下代码段添加到pom中来实现这一点:
org.springframework.boot
SpringBootStarterWeb
org.springframework.boot
弹簧启动机tomcat
org.springframework.boot
弹簧靴起动器码头
@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;
}
});
}
}