【问题标题】:TLS and Client Auth in Spring IntegrationSpring 集成中的 TLS 和客户端身份验证
【发布时间】:2019-09-04 14:41:17
【问题描述】:

我正在我的应用程序中试验 TLS、双向 TLS 和主机验证,并且对集成组件的行为有些困惑。我正在使用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 的唯一方法是将密钥库和信任库都传递给它。为什么需要密钥库?如果我的服务器不需要客户端身份验证,我不应该将密钥库传递给我的客户端连接工厂。客户端工厂应该只需要有一个信任库,以验证它正在与之交谈的服务器。

关于客户端身份验证,我的配置中的服务器连接工厂是否需要客户端身份验证?根据reference,为了启用客户端身份验证,我需要覆盖postProcessServerSocket() 方法。但是,在将客户端的证书添加到服务器的信任库之前,我遇到了 SSL 读取异常。为什么有必要,因为我还没有启用客户端身份验证?

最后,如果客户端连接工厂在其密钥库中确实有一个私钥条目,它会在打开与服务器的连接时自动使用该密钥吗?或者仅当服务器要求客户端身份验证时?似乎我的客户端连接工厂正在使用它的私钥,即使我还没有设置任何东西来强制客户端身份验证。

【问题讨论】:

    标签: spring-integration


    【解决方案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。

    【讨论】:

    • 请注意,服务器套接字也有 setWantsClientAuth - 也许默认为 true 可以解释您观察到的情况。我还没有测试过。
    • 你能重新发布测试用例的链接吗?该链接也可以返回到参考文档
    • 对不起;链接已修复。
    猜你喜欢
    • 2016-07-09
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 2013-07-20
    • 2016-01-21
    • 2016-10-11
    • 1970-01-01
    • 2019-01-24
    相关资源
    最近更新 更多