16
16
17
17
package org .springframework .amqp .rabbit .connection ;
18
18
19
+ import java .lang .reflect .Method ;
19
20
import java .net .URI ;
20
21
import java .net .URISyntaxException ;
21
22
import java .security .KeyManagementException ;
22
23
import java .security .KeyStore ;
23
- import java .security .KeyStoreException ;
24
24
import java .security .NoSuchAlgorithmException ;
25
25
import java .security .SecureRandom ;
26
26
import java .util .Arrays ;
27
27
import java .util .Map ;
28
28
import java .util .Properties ;
29
29
import java .util .concurrent .ExecutorService ;
30
30
import java .util .concurrent .ThreadFactory ;
31
+ import java .util .concurrent .atomic .AtomicReference ;
31
32
32
33
import javax .net .SocketFactory ;
33
34
import javax .net .ssl .KeyManager ;
42
43
import org .springframework .beans .factory .config .AbstractFactoryBean ;
43
44
import org .springframework .core .io .Resource ;
44
45
import org .springframework .core .io .support .PathMatchingResourcePatternResolver ;
46
+ import org .springframework .util .Assert ;
47
+ import org .springframework .util .ReflectionUtils ;
48
+ import org .springframework .util .ReflectionUtils .MethodCallback ;
49
+ import org .springframework .util .ReflectionUtils .MethodFilter ;
45
50
import org .springframework .util .StringUtils ;
46
51
47
52
import com .rabbitmq .client .ConnectionFactory ;
75
80
*/
76
81
public class RabbitConnectionFactoryBean extends AbstractFactoryBean <ConnectionFactory > {
77
82
83
+ private static final Method enableHostnameVerificationNoArgMethod ;
84
+
85
+ static {
86
+ final AtomicReference <Method > method1 = new AtomicReference <Method >();
87
+ ReflectionUtils .doWithMethods (ConnectionFactory .class , new MethodCallback () {
88
+
89
+ @ Override
90
+ public void doWith (Method m ) throws IllegalArgumentException , IllegalAccessException {
91
+ if (m .getParameterTypes ().length == 0 ) {
92
+ method1 .set (m );
93
+ }
94
+ }
95
+
96
+ }, new MethodFilter () {
97
+
98
+ @ Override
99
+ public boolean matches (Method m ) {
100
+ return m .getName ().equals ("enableHostnameVerification" );
101
+ }
102
+
103
+ });
104
+ enableHostnameVerificationNoArgMethod = method1 .get ();
105
+ }
106
+
78
107
private final Log logger = LogFactory .getLog (getClass ());
79
108
80
109
private static final String KEY_STORE = "keyStore" ;
@@ -103,30 +132,32 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean<ConnectionF
103
132
104
133
private Resource sslPropertiesLocation ;
105
134
106
- private volatile String keyStore ;
135
+ private String keyStore ;
107
136
108
- private volatile String trustStore ;
137
+ private String trustStore ;
109
138
110
- private volatile Resource keyStoreResource ;
139
+ private Resource keyStoreResource ;
111
140
112
- private volatile Resource trustStoreResource ;
141
+ private Resource trustStoreResource ;
113
142
114
- private volatile String keyStorePassphrase ;
143
+ private String keyStorePassphrase ;
115
144
116
- private volatile String trustStorePassphrase ;
145
+ private String trustStorePassphrase ;
117
146
118
- private volatile String keyStoreType ;
147
+ private String keyStoreType ;
119
148
120
- private volatile String trustStoreType ;
149
+ private String trustStoreType ;
121
150
122
- private volatile String sslAlgorithm = TLS_V1_1 ;
151
+ private String sslAlgorithm = TLS_V1_1 ;
123
152
124
- private volatile boolean sslAlgorithmSet ;
153
+ private boolean sslAlgorithmSet ;
125
154
126
- private volatile SecureRandom secureRandom ;
155
+ private SecureRandom secureRandom ;
127
156
128
157
private boolean skipServerCertificateValidation ;
129
158
159
+ private boolean enableHostnameVerification ;
160
+
130
161
public RabbitConnectionFactoryBean () {
131
162
this .connectionFactory .setAutomaticRecoveryEnabled (false );
132
163
}
@@ -604,6 +635,21 @@ public void setChannelRpcTimeout(int channelRpcTimeout) {
604
635
this .connectionFactory .setChannelRpcTimeout (channelRpcTimeout );
605
636
}
606
637
638
+ /**
639
+ * Enable server hostname verification for TLS connections.
640
+ * <p>
641
+ * This enables hostname verification regardless of the IO mode used (blocking or
642
+ * non-blocking IO).
643
+ * Requires amqp-client 5.4.0 or later.
644
+ * @param enable true to enable.
645
+ * @since 1.7.10
646
+ */
647
+ public void setEnableHostnameVerification (boolean enable ) {
648
+ Assert .notNull (enableHostnameVerificationNoArgMethod ,
649
+ "Host name verification requires amqp-client 5.4.0 or later" );
650
+ this .enableHostnameVerification = enable ;
651
+ }
652
+
607
653
@ Override
608
654
public Class <?> getObjectType () {
609
655
return ConnectionFactory .class ;
@@ -686,6 +732,7 @@ protected void setUpSSL() throws Exception {
686
732
SSLContext context = createSSLContext ();
687
733
context .init (keyManagers , trustManagers , this .secureRandom );
688
734
this .connectionFactory .useSslProtocol (context );
735
+ checkHostVerification ();
689
736
}
690
737
}
691
738
@@ -701,14 +748,20 @@ protected SSLContext createSSLContext() throws NoSuchAlgorithmException {
701
748
}
702
749
703
750
704
- private void useDefaultTrustStoreMechanism ()
705
- throws NoSuchAlgorithmException , KeyManagementException , KeyStoreException {
751
+ private void useDefaultTrustStoreMechanism () throws Exception {
706
752
SSLContext sslContext = SSLContext .getInstance (this .sslAlgorithm );
707
753
TrustManagerFactory trustManagerFactory =
708
754
TrustManagerFactory .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
709
755
trustManagerFactory .init ((KeyStore ) null );
710
756
sslContext .init (null , trustManagerFactory .getTrustManagers (), null );
711
757
this .connectionFactory .useSslProtocol (sslContext );
758
+ checkHostVerification ();
759
+ }
760
+
761
+ private void checkHostVerification () throws Exception {
762
+ if (this .enableHostnameVerification ) {
763
+ enableHostnameVerificationNoArgMethod .invoke (this .connectionFactory );
764
+ }
712
765
}
713
766
714
767
}
0 commit comments