我正在我的应用程序中尝试使用TLS,双向TLS和主机验证,并且对Integration组件的行为有些困惑。我正在使用TcpNetClientConnection
工厂和TcpNetServerConnectionFactory
。我对这些组件如何在幕后进行交互没有深刻的了解,并且想要确保我的身份验证按预期工作(或不工作)。
@Bean
public TcpNetClientConnectionFactory tcpClientConnectionFactory() {
TcpNetClientConnectionFactory factory =
new TcpNetClientConnectionFactory(upstreamHost, upstreamPort);
factory.setTcpSocketFactorySupport(tcpSslSocketFactorySupport);
factory.setTcpSocketSupport(new DefaultTcpSocketSupport(isHostVerificationEnabled));
return factory;
}
@Bean
TcpNetServerConnectionFactory testTcpServerConnectionFactory() {
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(upstreamPort);
factory.setTcpSocketFactorySupport(tcpSslSocketFactorySupport);
factory.setTcpSocketSupport(new DefaultTcpSocketSupport(isHostVerificationEnabled));
return factory;
}
@Bean
public DefaultTcpNetSSLSocketFactorySupport tcpSslSocketFactorySupport() {
TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport(keyStore, trustStore, keyStorePassword,
trustStorePassword);
return new DefaultTcpNetSSLSocketFactorySupport(sslContextSupport);
}
似乎创建TcpSSLContextSupport
的唯一方法是将密钥库和信任库都传递给它。为什么需要密钥库?如果我的服务器不需要客户端身份验证,则不必将密钥库传递给客户端连接工厂。客户端工厂只需要拥有一个信任库即可验证与之通信的服务器。
关于客户端身份验证,我配置中的服务器连接工厂是否需要客户端身份验证?根据{{3}},为了启用客户端身份验证,我需要重写postProcessServerSocket()
方法。但是,直到将客户端的证书添加到服务器的信任库中之前,我一直在获取SSL读取异常。既然我还没有启用客户端身份验证,那为什么有必要?
最后,如果客户端连接工厂的密钥库中确实有私钥条目,那么在打开与服务器的连接时,它会自动利用该密钥吗?还是仅在服务器要求客户端身份验证时?似乎我的客户端连接工厂正在使用其私钥,即使我尚未设置任何强制客户端认证的权限。
答案 0 :(得分:1)
默认情况下,服务器不需要clientAuth;有一个example in the documentation about how to require it。
请参见this test case。
如果我将第437行的代码注释掉
server.setTcpSocketSupport(new DefaultTcpSocketSupport(false) {
@Override
public void postProcessServerSocket(ServerSocket serverSocket) {
// ((SSLServerSocket) serverSocket).setNeedClientAuth(true);
}
});
测试失败
java.lang.AssertionError:
Expecting code to raise a throwable.
at org.springframework.integration.ip.tcp.connection.SocketSupportTests.testNetClientAndServerSSLDifferentContexts(SocketSupportTests.java:414)
assertThatExceptionOfType(MessagingException.class)
.isThrownBy(() -> testNetClientAndServerSSLDifferentContexts(true));
是的,默认实现需要一个密钥库,但是当不需要客户端身份验证时,它可以为空或不包含客户端密钥。我们应该放松一下;随时打开GitHub问题进行请求。和/或您可以简单地提供自己的实现。
在测试用例(可能会失败)中,我们使用不包含客户端证书的keyStore。
TcpSSLContextSupport clientSslContextSupport = new DefaultTcpSSLContextSupport(
badClient ? "server.ks" : "client.ks",
"client.truststore.ks", "secret", "secret");
请注意,服务器套接字还具有setWantsClientAuth
-可能默认为true
,这将解释您观察到的内容(如果在客户端提供证书,则会失败)。我还没有测试过尝试将其设置为false。