我目前已经在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,它将一个新的Trust Manager添加到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。哪个也没有用。

更新2:

我当前的解决方案基于这些链接,这些链接是针对Java的,但是我不确定如何在Spring Application中实现它们。
  • https://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/

  • 我快到了:

    我找到了一个解决方案,该解决方案准确描述了如何创建动态信任库。
    但是我无法弄清楚如何在运行时重新加载信任存储。例如说当调用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并从某种证书服务中调用它来完成-或将其公开并直接调用。这是你的选择。

    09-10 07:47
    查看更多