我目前已经在我的Spring应用程序中实现了相互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端点时。
没有本地信任存储的客户证书身份验证我有一个证书列表,我只需要知道如何调用ReloadableX509TrustManager的addCertificates()方法。
发布于 2019-07-23 11:13:55
首先,使您的ReloadableX509TrustManager成为托管bean (如用@Component注释)。
@Component
class ReloadableX509TrustManager
implements X509TrustManager {
.....
public ReloadableX509TrustManager(@Value("someValueFromAppConfig")String tspath){....}
.....第二,在控制器中使用它,而不是创建新的控制器。
@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;
}然后,跟随文章了解如何“重新加载”信任管理器。它可以通过更改大多数方法来实现,这些方法可以打包、保护并从某种服务器服务中调用它--或者将其公开并直接调用。是你的选择。
发布于 2019-07-24 13:11:46
更新2 : 我目前的解决方案是基于这些链接的,这些链接是针对Java的,但我不知道如何在Spring应用程序中实现它们。 https://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/
不管是不是春天,您的主要目标在广义上并不需要对应用程序技术的限制,重要的是您的应用程序(客户端)--它将是--能够在运行时期间的任意时刻将新的证书加载到客户端,并在运行时中进行更改。让我们这样说,我们可以在我们的类(TrustManager)中实现我们的逻辑,实现X509TrustManager。
在客户端实现信任管理器
这里的目标是告诉运行时,您希望使用这个新类来验证证书。我们必须用我们的SSLContext实例化一个新的SSLSocketFactory,并使用它来指定一个新的SSLSocketFactory。
try {
String trustStorePath = "path to a truststore that you have";
String trustStorePassword = "password of trustStore";
String defaultTrustStore = "path to default truststore";
// Initialize the new trustManager with the default trust store
TrustManager trustManager = new TrustManager(defaultTrustStore);
// Load the new Keystore and decrypt it
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
// Add all of the certficates in the truststore and add them to the trust manager
Enumeration<String> enumerator = ks.aliases();
ArrayList<Certificate> certs = new ArrayList<>();
while (enumerator.hasMoreElements()) {
String currentAlias = enumerator.nextElement();
certs.add(ks.getCertificate(currentAlias));
}
trustManager.addCertificates(certs);
// Initialize the SSLContext and add it to the client conduit.
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] {trustManager}, null);
// Set the new TrustManager in the client.
HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(service).getConduit();
TLSClientParameters tlsCP = new TLSClientParameters();
httpConduit.setTlsClientParameters(tlsCP);
tlsCP.setSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}如果你需要一个参考,这里,你会找到它。
发布于 2019-08-02 21:36:56
我还经历了同样的场景,在这个场景中,我必须动态更新我的spring的TrustManager。
https://stackoverflow.com/questions/57143673
复制相似问题