【问题标题】:How to load .keystore with multiple certs in SpringBoot如何在 Spring Boot 中加载具有多个证书的 .keystore
【发布时间】:2018-12-12 00:23:11
【问题描述】:

我正在开发 Spring Boot Application v2.0。从我的 Spring Boot 应用程序中,我发送 SOAP 请求以从 Soap WS 获取数据。我对不同的 Soap Web 服务有多个 Soap 请求。每个 Soap WS 都有自己的证书。我使用 Apache CXF v3.2.4 自动生成“ws 客户端”类以及 WS 的所有其他内容。

证书采用 PFX 格式。我已经通过 keytool 成功创建了密钥库。我尝试使用此代码设置 ssl.keyStore (这也不是设置这些值的好方法,我认为最好在应用程序属性中进行...:

System.setProperty("javax.net.ssl.keyStore","path to my keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "mypassword");

我的密钥库中有 3 个不同的证书。它们都经过单独测试,如果它们只有一个在密钥库中,它们都可以正常工作。问题是,当我在密钥库中有 3 个证书时,只加载列表中的第一个。

我在互联网上阅读了多篇文章,这篇文章最有趣但不幸的是它没有解决我的问题(Registering multiple keystores in JVM)。

如果我通过别名浏览证书链,我可以在控制台中看到所有证书。

 String storename = "C:/Certificates/mykeystore.ks";
            char[] storepass = "mypassword".toCharArray();
            String alias = "myalias";
            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream(storename), storepass);             
            java.security.cert.Certificate[] cchain = ks.getCertificateChain(alias);            
            List mylist = new ArrayList();
        for (int i = 0; i < cchain.length; i++) {                 
            mylist.add(cchain[i]);
            }
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            CertPath cp = cf.generateCertPath(mylist);
            System.out.println(cp);

你有什么建议吗?!我应该怎么做才能达到可以加载一个带有多个证书的密钥库或任何可以工作的阶段? 提前致谢。

附言我还尝试通过 Portecle 将这些证书放入 jdk/jre/lib/security/cacerts 但没有效果。

【问题讨论】:

    标签: spring-boot ssl-certificate cxf keystore soap-client


    【解决方案1】:

    对于每个 Web 服务,我认为您应该分别处理密钥库(和/或信任库)并在 application.properties 文件中进行配置。下面是使用特定证书集为 Url Connection 实例化 SocketFactory 的可行示例。

    application.properties

    keystore1.Path = src/main/resources/jks/yourKeyStoreFile1
    keystore1.Password = keystore1pwd
    truststore1.Path = src/main/resources/security1/cacerts
    truststore1.Password = truststore1pwd
    
    keystore2.Path = src/main/resources/jks/yourKeyStoreFile2
    keystore2.Password = keystore2pwd
    truststore2.Path = src/main/resources/security2/cacerts
    truststore2.Password = truststore2pwd
    

    当您使用不同的 WebService 时,请使用不同的 SocketFactory。以下是 .p12 密钥库和 .jks 信任库(证书)的示例。您可以轻松地将证书类型转换为不同的格式。

    @Component
    public class MySocketFactory {
    
        @Value("${keystore1.Path}")
        String keystore1Path;
    
        @Value("${keystore1.Password}")
        String keystore1Password;
    
        @Value("${truststore1.Path}")
        String truststore1Path;
    
        @Value("${truststore1.Password}")
        String truststore1Password;
    
        public MySocketFactory() {
    
        }
    
        public SSLSocketFactory getSocketFactory() {
    
            try {
    
                SSLContext context = SSLContext.getInstance("TLS");
    
                KeyManagerFactory keyMgrFactory = KeyManagerFactory.getInstance("SunX509");
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                char[] keyStorePassword = keystore1Password.toCharArray();
                keyStore.load(new FileInputStream(keystore1Path), keyStorePassword);
                keyMgrFactory.init(keyStore, keyStorePassword);
    
                TrustManagerFactory trustStrFactory = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                KeyStore trustStore = KeyStore.getInstance("JKS");
                char[] trustStorePassword = truststore1Password.toCharArray();
                trustStore.load(new FileInputStream(truststore1Path), trustStorePassword);
                trustStrFactory.init(trustStore);
    
                context.init(keyMgrFactory.getKeyManagers(), trustStrFactory.getTrustManagers(), null);
                return context.getSocketFactory();
    
            } catch (Exception e) {
                System.err.println("Failed to create a server socket factory...");
                e.printStackTrace();
                return null;
            }
        }
    }
    

    为第二个 SocketFactory 创建相同的内容。希望这会有所帮助。

    【讨论】:

    • 这在我的动态 Web 项目测试应用程序中帮助了我很多,但仍然不适用于 Spring Boot 2.0.3。我认为这可能与 Spring Boot 和嵌入式 Tomcat 有关。我根本无法初始化密钥库...我总是得到[nio-8080-exec-1] org.apache.cxf.transport.https.SSLUtils : Default key managers cannot be initialized: null
    • 我也试过 BindingProvider BindingProvider bindingProvider = (BindingProvider) port; bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getSocketFactory(truststorePath,trustStorePass));
    • 您是否将 SocketFactory @Autowired 放入需要使用 SocketFactory 的服务客户端类中?你只需要自动装配,不需要实例化。
    猜你喜欢
    • 1970-01-01
    • 2022-10-18
    • 2018-11-03
    • 2020-10-23
    • 2013-03-31
    • 1970-01-01
    • 2014-11-25
    • 2021-11-25
    • 1970-01-01
    相关资源
    最近更新 更多