草庐IT

spring 集成 TCP TLS 客户端身份验证

coder 2023-09-19 原文

我需要创建一个 TCP/TLS 服务器来执行客户端验证的 TLS 握手。 我正在使用 Spring Boot 和 tcp-inbound-gateway 来接受 TCP 连接。

配置如下:

<context:component-scan base-package="com.mycompany"/>

<int-ip:tcp-connection-factory id="crLfServer"
                               deserializer="myDeserializer"
                               serializer="serverSerializer"
                               single-use="false"
                               type="server"
                               ssl-context-support="mySslContext"
                               port="${local.server.port}"/>

<int-ip:tcp-inbound-gateway id="gatewayCrLf"
                            connection-factory="crLfServer"
                            request-channel="serverInChannel"
                            reply-channel="serverOutChannel"
                            error-channel="errorChannel"/>

<int:channel id="serverOutChannel"/>
<int:channel id="serverInChannel"/>

<int:service-activator input-channel="serverInChannel"
                       ref="transferService"
                       method="printService"/>

SSL上下文:

@Component
public class MySslContext extends DefaultTcpSSLContextSupport {
    public MySslContext(
            @Value("serverKeyStore.key") String keyStore,
            @Value("serverOnlyTS.key") String trustStore,
            @Value("123456") String keyStorePassword,
            @Value("123456") String trustStorePassword) {

        super(keyStore, trustStore, keyStorePassword, trustStorePassword);
    }
}

TransferService 做了一个非常简单的工作:

public Message<byte[]> printService(Message<byte[]> m){
        log.info("Message received from client: " + m.getPayload());
        return m;
    }

另一方面,我配置了一个与服务器通信的简单客户端:

 <int-ip:tcp-connection-factory
             id="clientCF"
             type="client"
             host="127.0.0.1"
             port="4444"
             single-use="false"
             lookup-host="false"
             serializer="directSerializer"
             ssl-context-support="myClientSslContext"/>

  <bean id="myClientSslContext" class="org.springframework.integration.ip.tcp.connection.DefaultTcpSSLContextSupport">
        <constructor-arg index="0" value="clientKeyStore.key"/>
        <constructor-arg index="1" value="serverOnlyTS.key"/>
        <constructor-arg index="2" value="123456"/>
        <constructor-arg index="3" value="123456"/>
    </bean>

    <bean id="directSerializer" class="com.mycompany.DirectSerializer">
        <constructor-arg value="clientSer"/>
    </bean>

    <int-ip:tcp-outbound-gateway id="outGateway"
                                 request-channel="clientOutChannel"
                                 reply-channel="clientInChannel"
                                 connection-factory="clientCF"/>

    <int:channel id="clientOutChannel"/>
    <int:channel id="clientInChannel"/>

客户端以这段代码开始:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        byte[] message = {11,11,11,11,11,11,11,11,11,11};
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ssl-client.xml");
        DirectChannel c= (DirectChannel) context.getBean("clientOutChannel");
        c.send(MessageBuilder.withPayload(message).build());
    }
}

serverKeyStore.key 被导入到信任库serverOnlyTS.key(客户端和服务器都使用这个信任库),clientKeyStore.key未导入任何信任库。

根据这篇文章:How to setup TLS Server to authenticate client in spring integration?, 我希望我的服务器将执行客户端身份验证并只接受使用 serverKeyStore.key 的连接。

事实上,当我运行客户端时,我的服务器正确接收消息并且我看到这个输出:(-Djavax.net.debug=ssl)

Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
pool-1-thread-1, setSoTimeout(0) called
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
........
pool-1-thread-3, READ: TLSv1.2 Handshake, length = 193
*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1482858633 bytes = { 81, 115, 166, 218, 194, 111, 29, 83, 96, 23, 240, 122, 118, 11, 1, 62, 52, 12, 102, 69, 151, 215, 180, 42, 76, 192, 48, 197 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
***
%% Initialized:  [Session-2, SSL_NULL_WITH_NULL_NULL]
%% Negotiating:  [Session-2, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256]
*** ServerHello, TLSv1.2
RandomCookie:  GMT: 1482858633 bytes = { 242, 158, 132, 149, 150, 9, 60, 231, 104, 29, 171, 220, 15, 164, 169, 111, 78, 8, 179, 209, 168, 190, 62, 220, 53, 119, 152, 91 }
Session ID:  {88, 99, 161, 137, 97, 86, 192, 141, 13, 111, 100, 231, 192, 248, 131, 25, 159, 39, 121, 17, 133, 96, 208, 197, 116, 214, 200, 49, 171, 203, 172, 99}
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
Cipher suite:  TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: CN=gena j, OU=dev, O=cg, L=il, ST=il, C=il
  Signature Algorithm: SHA1withDSA, OID = 1.2.840.10040.4.3

  Key:  Sun DSA Public Key
    Parameters:DSA
    p:     fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80 b6512669
    455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b 801d346f f26660b7
    6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6 1bf83b57 e7c6a8a6 150f04fb
    83f6d3c5 1ec30235 54135a16 9132f675 f3ae2b61 d72aeff2 2203199d d14801c7
    q:     9760508f 15230bcc b292b982 a2eb840b f0581cf5
    g:     f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b 3d078267
    5159578e bad4594f e6710710 8180b449 167123e8 4c281613 b7cf0932 8cc8a6e1
    3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f 0bfa2135 62f1fb62 7a01243b
    cca4f1be a8519089 a883dfe1 5ae59f06 928b665e 807b5525 64014c3b fecf492a

  y:
    09356efb 5c421633 dc73eeee 7389d573 20a54fed eba1cc95 c2c451da 38a8ec10
    04c80b53 57c712fa 536b05aa 3f497153 58bb8e70 691d4cd6 3d9ab0e1 f14a005d
    16c4ad2b dadf91ff fbfcae4f dadcbede 35e90b9f a8e37ec6 e28f78f5 269fee9e
    8cb96fa5 d36b3ac3 059195c7 0a586484 6fc84493 764f27ce e127192d 252fd94a

  Validity: [From: Wed Dec 28 11:33:01 IST 2016,
               To: Tue Mar 28 12:33:01 IDT 2017]
  Issuer: CN=gena j, OU=dev, O=cg, L=il, ST=il, C=il
  SerialNumber: [    6c326fb1]

Certificate Extensions: 1
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A1 84 23 95 00 CA 92 06   AC DB E7 E9 43 39 48 7E  ..#.........C9H.
0010: 9F 1B A2 1E                                        ....
]
]

]
  Algorithm: [SHA1withDSA]
  Signature:
0000: 30 2D 02 14 2E FB 00 B3   62 8F 3A C3 7E C3 EC 18  0-......b.:.....
0010: 6A 67 B2 97 A2 C9 62 25   02 15 00 92 F8 2E 97 3E  jg....b%.......>
0020: 29 1F 3B 5D 8A 7A DE D4   5D 76 09 56 35 53 21     ).;].z..]v.V5S!

]
***
*** Diffie-Hellman ServerKeyExchange
DH Modulus:  { 255, 255, 255, 255, 255, 255, 255, 255, 201, 15, 218, 162, 33, 104, 194, 52, 196, 198, 98, 139, 128, 220, 28, 209, 41, 2, 78, 8, 138, 103, 204, 116, 2, 11, 190, 166, 59, 19, 155, 34, 81, 74, 8, 121, 142, 52, 4, 221, 239, 149, 25, 179, 205, 58, 67, 27, 48, 43, 10, 109, 242, 95, 20, 55, 79, 225, 53, 109, 109, 81, 194, 69, 228, 133, 181, 118, 98, 94, 126, 198, 244, 76, 66, 233, 166, 55, 237, 107, 11, 255, 92, 182, 244, 6, 183, 237, 238, 56, 107, 251, 90, 137, 159, 165, 174, 159, 36, 17, 124, 75, 31, 230, 73, 40, 102, 81, 236, 230, 83, 129, 255, 255, 255, 255, 255, 255, 255, 255 }
DH Base:  { 2 }
Server DH Public Key:  { 76, 1, 47, 15, 147, 255, 144, 196, 90, 71, 173, 116, 138, 121, 159, 38, 249, 6, 152, 219, 59, 126, 193, 34, 64, 24, 25, 172, 100, 252, 76, 120, 215, 194, 111, 10, 106, 161, 31, 221, 17, 10, 119, 13, 224, 212, 69, 169, 14, 139, 241, 129, 171, 126, 55, 165, 254, 5, 22, 216, 16, 119, 65, 36, 235, 223, 41, 58, 112, 71, 212, 137, 185, 126, 226, 45, 26, 216, 150, 28, 145, 203, 73, 4, 188, 9, 173, 124, 166, 50, 39, 99, 40, 105, 13, 16, 228, 140, 99, 143, 228, 167, 12, 171, 87, 50, 205, 193, 223, 3, 113, 43, 27, 87, 63, 45, 210, 186, 36, 102, 164, 223, 181, 254, 150, 56, 67, 19 }
Signature Algorithm SHA256withDSA
Signed with a DSA or RSA public key
*** ServerHelloDone
pool-1-thread-3, WRITE: TLSv1.2 Handshake, length = 1188
pool-1-thread-3, READ: TLSv1.2 Handshake, length = 134
*** ClientKeyExchange, DH
DH Public key:  { 195, 132, 198, 83, 122, 44, 17, 51, 121, 11, 125, 243, 215, 195, 28, 209, 241, 218, 233, 233, 40, 141, 63, 184, 104, 159, 85, 29, 70, 15, 37, 14, 236, 143, 255, 67, 96, 0, 23, 115, 109, 22, 235, 32, 215, 28, 116, 15, 206, 56, 249, 72, 246, 181, 203, 65, 107, 205, 20, 240, 150, 121, 55, 59, 154, 62, 202, 31, 55, 232, 235, 167, 45, 155, 232, 62, 205, 203, 188, 164, 213, 202, 81, 114, 202, 124, 160, 28, 252, 229, 225, 87, 47, 225, 111, 57, 163, 187, 152, 176, 200, 249, 26, 103, 4, 243, 204, 60, 146, 28, 175, 196, 5, 47, 107, 216, 18, 28, 36, 202, 136, 219, 118, 96, 53, 218, 24, 209 }
SESSION KEYGEN:
PreMaster Secret:
0000: E6 82 09 78 D2 9D 3C F3   60 57 97 DD 18 32 E5 92  ...x..<.`W...2..
0010: BC A6 CC 62 90 F3 D6 1E   23 0B 3C CE 10 92 9C 11  ...b....#.<.....
0020: DB AF B6 89 20 72 DB D6   8E F2 26 59 38 B1 67 E9  .... r....&Y8.g.
0030: FF E3 97 8F 55 1E 32 A5   A7 BB 62 14 E9 67 0E 5F  ....U.2...b..g._
0040: DF C4 98 5C 29 E3 02 DB   1F 57 93 5C 9B 43 26 8D  ...\)....W.\.C&.
0050: E3 06 D6 06 61 7D 19 99   B5 CE C8 D2 53 74 82 0C  ....a.......St..
0060: 3E 44 EC B0 D4 71 F2 55   73 D3 66 B2 F3 AB 37 AE  >D...q.Us.f...7.
0070: 18 01 8F BC FE 54 4F 8D   6F AD 59 FD 87 E5 5A 72  .....TO.o.Y...Zr
CONNECTION KEYGEN:
Client Nonce:
0000: 58 63 A1 89 51 73 A6 DA   C2 6F 1D 53 60 17 F0 7A  Xc..Qs...o.S`..z
0010: 76 0B 01 3E 34 0C 66 45   97 D7 B4 2A 4C C0 30 C5  v..>4.fE...*L.0.
Server Nonce:
0000: 58 63 A1 89 F2 9E 84 95   96 09 3C E7 68 1D AB DC  Xc........<.h...
0010: 0F A4 A9 6F 4E 08 B3 D1   A8 BE 3E DC 35 77 98 5B  ...oN.....>.5w.[
Master Secret:
0000: C5 89 9E 61 C3 94 89 72   8B 16 34 05 9C 54 69 D2  ...a...r..4..Ti.
0010: DE 02 50 93 98 98 42 2F   B5 A6 D7 90 11 AD B2 AE  ..P...B/........
0020: 9A 76 6E 48 B2 6B 1B BC   94 42 92 FC 59 58 6F BA  .vnH.k...B..YXo.
Client MAC write Secret:
0000: 5F 43 41 51 5C D2 F1 4C   5A 33 4B 0E F8 A4 09 DF  _CAQ\..LZ3K.....
0010: 7B 3A 83 EA 62 23 C1 F2   38 AB FD 92 F1 F3 33 74  .:..b#..8.....3t
Server MAC write Secret:
0000: B8 14 DF 6F AC AA 29 34   F6 68 6E 4F 76 2A 94 B2  ...o..)4.hnOv*..
0010: CB CB F5 66 EE 5F 3F 8F   AF E4 AA 8A 29 C2 04 4F  ...f._?.....)..O
Client write key:
0000: 39 A7 98 73 C7 49 0E D5   1E 92 45 C7 9F DE D7 91  9..s.I....E.....
Server write key:
0000: BE AC 70 EF 2E 58 72 42   71 38 89 DF F1 AF 15 62  ..p..XrBq8.....b
... no IV derived for this protocol
pool-1-thread-3, READ: TLSv1.2 Change Cipher Spec, length = 1
pool-1-thread-3, READ: TLSv1.2 Handshake, length = 80
*** Finished
verify_data:  { 27, 30, 80, 199, 171, 151, 17, 231, 188, 152, 123, 58 }
***
pool-1-thread-3, WRITE: TLSv1.2 Change Cipher Spec, length = 1
*** Finished
verify_data:  { 231, 12, 206, 159, 3, 117, 192, 43, 195, 31, 193, 139 }
***
pool-1-thread-3, WRITE: TLSv1.2 Handshake, length = 80
%% Cached server session: [Session-2, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256]
pool-1-thread-3, READ: TLSv1.2 Application Data, length = 64
28/12/16 13:27:05.397  [pool-1-thread-3] Message received from client: [B@66070151

我是 TLS 的新手,但我认为我需要在服务器进行客户端身份验证时看到 ***CertificateRequest

知道我错过了什么吗?

最佳答案

我们可能会让这更容易一些,但你必须配置一个 socket-support实例到 require client authentication .

当使用java配置时,你可以直接注入(inject)...

serverFactory.setTcpSocketSupport(new DefaultTcpSocketSupport() {

    @Override
    public void postProcessServerSocket(ServerSocket serverSocket) {
        ((SSLServerSocket) serverSocket).setNeedClientAuth(true);
    }

});

使用XML配置时,可以创建DefaultTcpSocketSupport的子类并传递对 <bean/> 的引用socket-support 中的那个类(class)服务器连接工厂的属性。

Documentation here .

关于spring 集成 TCP TLS 客户端身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41361470/

有关spring 集成 TCP TLS 客户端身份验证的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

  6. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  7. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  8. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  9. ruby-on-rails - 如何使辅助方法在 Rails 集成测试中可用? - 2

    我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel

  10. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

随机推荐