关于Netty、Spring Webflux以及如何向多个下游系统发送http请求的小问题,当每个下游系统都需要MTL并且需要不同的客户端证书来向每个系统发送请求时,请回答?
到目前为止,我在我的Java11 Spring WebFlow 2.4.2应用程序中发送请求是:
@Bean
@Primary
public WebClient getWebClient() {
return WebClient.create().mutate().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).clientConnector(new ReactorClientHttpConnector(HttpClient.create().wiretap(true).secure(sslContextSpec -> sslContextSpec.sslContext(getSslContext())))).build();
}
对于Netty SslContext(顺便说一句,它不是apache SslContext)
public SslContext getSslContext() {
try {
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
try (InputStream file = new FileInputStream(keyStorePath)) {
final KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(file, keyStorePassPhrase.toCharArray());
keyManagerFactory.init(keyStore, keyPassPhrase.toCharArray());
}
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
try (InputStream trustStoreFile = new FileInputStream(trustStorePath)) {
final KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(trustStoreFile, trustStorePassPhrase.toCharArray());
trustManagerFactory.init(trustStore);
}
return SslContextBuilder.forClient().keyManager(keyManagerFactory).trustManager(trustManagerFactory).build();
} catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException | UnrecoverableKeyException e) {
return null;
}
}
当我们只需要向一个下游发送请求时,这甚至可以正常工作。
即使有多个下游,并且它们接受相同的客户机证书,这也是可行的!
但当每个下游都要求我使用各自的客户端证书时,问题就出现了。
请问如何做到这一点?
非常感谢。
最直接的解决方案是为每个下游api使用特定的客户端。并为每个客户端配置其特定的客户端密钥和信任材料。
但您的问题是:如何将SslContext与多个客户端证书一起使用?
所以我想给你一些代码示例来建立一个有效的设置。但简短的答案是:是的,这是可能的!
长话短说,您需要一些额外的配置才能使其工作。基本上,您需要做的是从keystore-1创建一个keymanagerfactory,并从keymanagerfactory获取keymanager,然后对其他两个keystore重复该操作。之后,您将拥有3个密钥管理器。下一步是有一种特殊的密钥管理器,可以提供给Netty SslContext。这种特殊类型的keymanager能够遍历您之前创建的3个keymanager,它将选择正确的密钥材料与服务器通信。您需要的是一个CompositeKeyManager和CompositeTrustManager,这在下面的stackoverflow答案中提到:在JVM中注册多个密钥库
实际的代码片段如下所示。我忽略了使用inputstream加载文件和创建密钥库文件以及创建keymanagerfactory,因为您已经知道如何做到这一点。
KeyManager keyManagerOne = keyManagerFactoryOne.getKeyManagers()[0]
KeyManager keyManagerTwo = keyManagerFactoryTwo.getKeyManagers()[0]
KeyManager keyManagerThree = keyManagerFactoryThree.getKeyManagers()[0]
List<KeyManager> keyManagers = new ArrayList<>();
keyManagers.add(keyManagerOne);
keyManagers.add(keyManagerTwo);
keyManagers.add(keyManagerThree);
CompositeX509KeyManager baseKeyManager = new CompositeX509KeyManager(keyManagers);
//repeat the same for the trust material
TrustManager trustManagerOne = trustManagerFactoryOne.getTrustManagers()[0]
TrustManager trustManagerTwo = trustManagerFactoryTwo.getTrustManagers()[0]
TrustManager trustManagerThree = trustManagerFactoryThree.getTrustManagers()[0]
List<TrustManager> trustManagers = new ArrayList<>();
trustManagers.add(trustManagerOne);
trustManagers.add(trustManagerTwo);
trustManagers.add(trustManagerThree);
CompositeX509TrustManager baseTrustManager = new CompositeX509TrustManager(trustManagers);
SslContext sslContext = SslContextBuilder.forClient()
.keyManager(baseKeyManager)
.trustManager(baseTrustManager)
.build();
上面的代码应该使您能够为单个客户端使用多个密钥和信任。该客户端将能够使用不同的密钥和信任材料与不同的下游api进行通信。
这种设置的缺点是,您需要将CompositeKeyManager和CompositeTrustManager复制并粘贴到您的代码库中,并且该设置有点冗长。Java没有为这个用例提供现成的东西。
如果您想要一个有点简单的设置,我建议您使用下面的代码片段:
import io.netty.handler.ssl.SslContext;
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.util.NettySslUtils;
public class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyStorePathOne, password)
.withIdentityMaterial(keyStorePathTwo, password)
.withIdentityMaterial(keyStorePathThree, password)
.withTrustMaterial(trustStorePathOne, password)
.withTrustMaterial(trustStorePathTwo, password)
.withTrustMaterial(trustStorePathThree, password)
.build();
SslContext sslContext = NettySslUtils.forClient(sslFactory).build();
}
}
我需要提供一些免责声明,我是上面代码片段库的维护者。该库在这里可用:GitHub-SSLContext Kickstart,它在我前面提到的选项2的封面下使用相同的CompositeKeyManager和CompositeTrustManager。
您可以使用以下代码片段将其添加到pom中:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-netty</artifactId>
<version>6.6.0</version>
</dependency>
问题内容: 我想要求基于Java 1.7内置HttpsServer的服务器进行客户端证书认证。 我似乎找不到任何使服务器无法通过身份验证的方法。无论客户端证书是受信任的,未知的还是完全不存在的,它都会愉快地为所有旧客户端提供数据。 我对文档的阅读建议,如果不信任客户端,则设置HttpsParameters.setNeedClientAuth(true)应该会导致身份验证失败。我发现有类似问题的人的
我在Jmeter中执行API时遇到了问题。我们的API中有客户端证书。pfx格式。我已经把它换成了。jks,并在系统中进行了更新。jmeter的特性。在jmeter中,我创建了一个csv文件来获取创建的别名。但是,错误显示为 错误:响应消息:非HTTP响应消息:java.lang.IllegalArgumentException:未找到别名的证书:'certalias' 以下是我的别名信息:别名:
我正在使用Netty4创建一个需要为多个客户端连接提供服务的服务器。ServerBootstrap由父线程组和工作线程组构成。根据ServerBootStrap上的文档。group()方法it “为父(接收器)和子(客户端)设置EventLoopGroup。这些EventLoopGroup用于处理SocketChannel和Channel的所有事件和IO。” 据我所知,ParentExecutor
问题内容: 这不是设计上应该发生的事情,但是出于安全考虑,我想知道,如果有多个证书与某个CA签署的要求相匹配,那么如何将“正确的”证书发送到服务器? 我正在使用一个简单的SSL JAVA示例客户端,连接到Apache HTTPD。 我尝试用4个证书进行测试,每次删除选择的证书,并记下下一个是谁。除了证书的“ sha256”的词典顺序之外,我找不到合理的逻辑(即日期,别名等)。在我看来这不太可能…
我有一个Java服务器应用程序,它通过TLS从GRPC客户端获取数据并在服务器上处理。现在我想使用多个客户端。要向客户端分配接收到的事件,我想读取客户端证书并使用证书的DN分配事件。如何获取客户端证书? 我发现这个构建服务器:https://github.com/grpc/grpc-java/blob/master/SECURITY.md#mutual-tls 然后你应该实现一个服务器拦截器 }
问题内容: 在我的Java应用程序中,我需要使用SSL连接到同一主机,但每次都使用不同的证书。我需要使用其他证书的原因是,远程站点使用嵌入在证书中的用户ID属性来标识客户端。 这是一个在3个不同的操作系统上运行的服务器应用程序,我需要能够在不重新启动进程的情况下切换证书。 问题答案: SSL可以向客户端提示要显示的证书。这 可能 使您可以使用一个具有多个身份的密钥存储,但是,不幸的是,大多数服务器