Spring集成中的TLS和客户端身份验证

时间:2019-08-30 20:59:36

标签: spring-integration

我正在我的应用程序中尝试使用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读取异常。既然我还没有启用客户端身份验证,那为什么有必要?

最后,如果客户端连接工厂的密钥库中确实有私钥条目,那么在打开与服务器的连接时,它会自动利用该密钥吗?还是仅在服务器要求客户端身份验证时?似乎我的客户端连接工厂正在使用其私钥,即使我尚未设置任何强制客户端认证的权限。

1 个答案:

答案 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。