java - 如何动态更新信任库?

标签 java spring spring-boot ssl truststore

我目前已经在我的 Spring Boot 应用程序中实现了双向 TLS,我正在以编程方式进行,如下所示:

@Bean
public ServletWebServerFactory servContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    TomcatConnectorCustomizer tomcatConnectorCustomizer = new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
            connector.setPort(8443);
            connector.setScheme("https");
            connector.setSecure(true);
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();

            protocol.setSSLEnabled(true);
            protocol.setKeystoreType("PKCS12");
            protocol.setKeystoreFile(keystorePath);
            protocol.setKeystorePass(keystorePass);
            //client must be authenticated (the cert he sends should be in our trust store)
            protocol.setSSLVerifyClient(Boolean.toString(true));
            protocol.setTruststoreFile(truststorePath);
            protocol.setTruststorePass(truststorePass);
            protocol.setKeyAlias("APP");
        }
    };
    tomcat.addConnectorCustomizers(tomcatConnectorCustomizer);
    return tomcat;
}

这工作正常并且符合预期,但我有一个要求,我需要在运行时更新信任库(例如,当调用 @getmapping 端点时)。

具体来说,我需要在不停止/重新启动应用程序的情况下将新证书添加到 TrustStore。 因此,我将不得不以某种方式修改我的应用程序的内存中信任库。

我该怎么做?

我尝试动态添加一个 bean,它将新的信任管理器添加到 SslContext,但这不起作用。

@GetMapping("/register")
public String Register() throws Exception {
    ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) appContext;
    ConfigurableListableBeanFactory beanRegistry = configContext.getBeanFactory();
    SSLContext sslContext = getSSLContext();
    beanRegistry.registerSingleton("sslContext", sslContext);
    return "okay";
}


public  SSLContext getSSLContext() throws Exception {
    TrustManager[] trustManagers = new TrustManager[] {
            new ReloadableX509TrustManager(truststoreNewPath)
    };
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustManagers, null);
    SSLContext.setDefault(sslContext);
    return sslContext;
}

我还尝试将上面的 getSSLContext() 作为 @bean 调用,但也没有用。

我当前的解决方案基于这些链接,它们适用于 Java,但我不确定如何在我的 Spring 应用程序中实现它们。

我找到了一个解决方案,它准确描述了如何拥有动态信任库,但我无法弄清楚如何在运行时重新加载信任库。例如,调用 GET 端点时。

Client Certificate authentication without local truststore 我有一个证书列表,我只需要知道如何调用 ReloadableX509TrustManageraddCertificates() 方法。

最佳答案

首先,使您的 ReloadableX509TrustManager 成为托管 bean - 例如使用 @Component 进行注释

@Component
class ReloadableX509TrustManager 
    implements X509TrustManager {
.....
    public ReloadableX509TrustManager(@Value("someValueFromAppConfig")String tspath){....}
.....

其次,在你的 Controller 中使用它而不是创建一个新的,例如

@GetMapping("/register")
public String Register() throws Exception {
    ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) appContext;
    ConfigurableListableBeanFactory beanRegistry = configContext.getBeanFactory();
    SSLContext sslContext = getSSLContext();
    beanRegistry.registerSingleton("sslContext", sslContext);
    return "okay";
}

@Autowired private ReloadableX509TrustManager reloadableManager;
public  SSLContext getSSLContext() throws Exception {
    TrustManager[] trustManagers = new TrustManager[] {
            reloadableManager
    };
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustManagers, null);
    SSLContext.setDefault(sslContext);
    return sslContext;
}

第三,按照文章了解如何“重新加载”该信任管理器。可以通过将大多数方法更改为 package protected 并从某种证书服务调用它来完成 - 或者将其公开并直接调用。选择权在您。

关于java - 如何动态更新信任库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57143673/

相关文章:

java - 如何在 "user.home"中创建目录?

java - spring boot init.d 脚本 start-stop-daemon : unrecognized option --no-close

hibernate - 使用 H2 自增

java - 无法自省(introspection)类 [org.keycloak.adapters.springboot.KeycloakAutoConfiguration]

java - 仅使用基元将元素动态添加到二维数组中

java - 如何显示非 Activity 类别的插页式广告?

spring - 使用 Java 将 Outlook 电子邮件以 .MSG 格式存储到磁盘

java - Spring Security BCrypt 总是寻找 “$2a” 正则表达式

java - 使用 Postgres 实现 Spring + Apache Flink 项目

java - 如果给定的查询参数无效或大小写不同,如何使 Spring MVC Controller 出错?