1515
1616package com .rabbitmq .client ;
1717
18- import static java .util .concurrent .TimeUnit .*;
19-
2018import com .rabbitmq .client .impl .AMQConnection ;
2119import com .rabbitmq .client .impl .ConnectionParams ;
2220import com .rabbitmq .client .impl .CredentialsProvider ;
3129import com .rabbitmq .client .impl .recovery .AutorecoveringConnection ;
3230import com .rabbitmq .client .impl .recovery .RetryHandler ;
3331import com .rabbitmq .client .impl .recovery .TopologyRecoveryFilter ;
32+ import org .apache .http .conn .ssl .DefaultHostnameVerifier ;
3433
34+ import javax .net .SocketFactory ;
35+ import javax .net .ssl .HostnameVerifier ;
36+ import javax .net .ssl .SSLContext ;
37+ import javax .net .ssl .SSLSocketFactory ;
38+ import javax .net .ssl .TrustManager ;
3539import java .io .IOException ;
3640import java .net .URI ;
3741import java .net .URISyntaxException ;
4953import java .util .concurrent .ScheduledExecutorService ;
5054import java .util .concurrent .ThreadFactory ;
5155import java .util .concurrent .TimeoutException ;
52- import javax .net .SocketFactory ;
53- import javax .net .ssl .SSLContext ;
54- import javax .net .ssl .SSLSocketFactory ;
55- import javax .net .ssl .TrustManager ;
56+
57+ import static java .util .concurrent .TimeUnit .MINUTES ;
5658
5759/**
5860 * Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker.
@@ -126,7 +128,7 @@ public class ConnectionFactory implements Cloneable {
126128 // connections uses, see rabbitmq/rabbitmq-java-client#86
127129 private ExecutorService shutdownExecutor ;
128130 private ScheduledExecutorService heartbeatExecutor ;
129- private SocketConfigurator socketConf = new DefaultSocketConfigurator ();
131+ private SocketConfigurator socketConf = SocketConfigurators . defaultConfigurator ();
130132 private ExceptionHandler exceptionHandler = new DefaultExceptionHandler ();
131133 private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider (DEFAULT_USER , DEFAULT_PASS );
132134
@@ -188,6 +190,19 @@ public class ConnectionFactory implements Cloneable {
188190 */
189191 private RetryHandler topologyRecoveryRetryHandler ;
190192
193+ /**
194+ * Hook to post-process the freshly open TCP connection.
195+ *
196+ * @since 4.8.0
197+ */
198+ private ConnectionPostProcessor connectionPostProcessor = new ConnectionPostProcessor () {
199+
200+ @ Override
201+ public void postProcess (ConnectionContext context ) {
202+
203+ }
204+ };
205+
191206 /** @return the default host to use for connections */
192207 public String getHost () {
193208 return host ;
@@ -679,12 +694,19 @@ public void useSslProtocol(String protocol)
679694 * Pass in the TLS protocol version to use, e.g. "TLSv1.2" or "TLSv1.1", and
680695 * a desired {@link TrustManager}.
681696 *
697+ * Note <strong>you must explicitly enable hostname verification</strong> with the
698+ * {@link ConnectionFactory#enableHostnameVerification()} or the
699+ * {@link ConnectionFactory#enableHostnameVerification(HostnameVerifier)}
700+ * method.
701+ *
682702 *
683703 * The produced {@link SSLContext} instance will be shared with all
684704 * the connections created by this connection factory.
685705 * @param protocol the TLS protocol to use.
686706 * @param trustManager the {@link TrustManager} implementation to use.
687707 * @see #useSslProtocol(SSLContext)
708+ * @see #enableHostnameVerification()
709+ * @see #enableHostnameVerification(HostnameVerifier)
688710 */
689711 public void useSslProtocol (String protocol , TrustManager trustManager )
690712 throws NoSuchAlgorithmException , KeyManagementException
@@ -699,15 +721,108 @@ public void useSslProtocol(String protocol, TrustManager trustManager)
699721 * for setting up the context with a {@link TrustManager} with suitable security guarantees,
700722 * e.g. peer verification.
701723 *
724+ * Note <strong>you must explicitly enable hostname verification</strong> with the
725+ * {@link ConnectionFactory#enableHostnameVerification()} or the
726+ * {@link ConnectionFactory#enableHostnameVerification(HostnameVerifier)}
727+ * method.
728+ *
702729 * The {@link SSLContext} instance will be shared with all
703730 * the connections created by this connection factory.
704731 * @param context An initialized SSLContext
732+ * @see #enableHostnameVerification()
733+ * @see #enableHostnameVerification(HostnameVerifier)
705734 */
706735 public void useSslProtocol (SSLContext context ) {
707736 setSocketFactory (context .getSocketFactory ());
708737 this .sslContext = context ;
709738 }
710739
740+ /**
741+ * Enable server hostname verification for TLS connections.
742+ * <p>
743+ * This enables hostname verification regardless of the IO mode
744+ * used (blocking or non-blocking IO).
745+ * <p>
746+ * This can be called typically after setting the {@link SSLContext}
747+ * with one of the <code>useSslProtocol</code> methods.
748+ * <p>
749+ * If <strong>using Java 7 or more</strong>, the hostname verification will be
750+ * performed by Java, as part of the TLS handshake.
751+ * <p>
752+ * If <strong>using Java 6</strong>, the hostname verification will be handled after
753+ * the TLS handshake, using the {@link HostnameVerifier} from the
754+ * Commons HttpClient project. This requires to add Commons HttpClient
755+ * and its dependencies to the classpath. To use a custom {@link HostnameVerifier},
756+ * use {@link ConnectionFactory#enableHostnameVerification(HostnameVerifier)}.
757+ *
758+ * @see NioParams#enableHostnameVerification()
759+ * @see NioParams#setSslEngineConfigurator(SslEngineConfigurator)
760+ * @see SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION
761+ * @see SocketConfigurators#ENABLE_HOSTNAME_VERIFICATION
762+ * @see ConnectionFactory#useSslProtocol(String)
763+ * @see ConnectionFactory#useSslProtocol(SSLContext)
764+ * @see ConnectionFactory#useSslProtocol()
765+ * @see ConnectionFactory#useSslProtocol(String, TrustManager)
766+ * @see ConnectionFactory#enableHostnameVerification(HostnameVerifier)
767+ * @since 4.8.0
768+ */
769+ public void enableHostnameVerification () {
770+ if (isJava6 ()) {
771+ enableHostnameVerification (new DefaultHostnameVerifier ());
772+ } else {
773+ enableHostnameVerificationForNio ();
774+ enableHostnameVerificationForBlockingIo ();
775+ }
776+ }
777+
778+ /**
779+ * Enable TLS hostname verification performed by the passed-in {@link HostnameVerifier}.
780+ * <p>
781+ * Using an {@link HostnameVerifier} is relevant only for Java 6, for Java 7 or more,
782+ * calling ConnectionFactory{@link #enableHostnameVerification()} is enough.
783+ *
784+ * @param hostnameVerifier
785+ * @since 4.8.0
786+ * @see ConnectionFactory#enableHostnameVerification()
787+ */
788+ public void enableHostnameVerification (HostnameVerifier hostnameVerifier ) {
789+ if (this .connectionPostProcessor == null ) {
790+ this .connectionPostProcessor = ConnectionPostProcessors .builder ()
791+ .enableHostnameVerification (hostnameVerifier )
792+ .build ();
793+ } else {
794+ this .connectionPostProcessor = ConnectionPostProcessors .builder ()
795+ .add (this .connectionPostProcessor )
796+ .enableHostnameVerification (hostnameVerifier )
797+ .build ();
798+ }
799+ }
800+
801+ protected boolean isJava6 () {
802+ return System .getProperty ("java.specification.version" ).startsWith ("1.6" );
803+ }
804+
805+ protected void enableHostnameVerificationForNio () {
806+ if (this .nioParams == null ) {
807+ this .nioParams = new NioParams ();
808+ }
809+ this .nioParams = this .nioParams .enableHostnameVerification ();
810+ }
811+
812+ protected void enableHostnameVerificationForBlockingIo () {
813+ if (this .socketConf == null ) {
814+ this .socketConf = SocketConfigurators .builder ()
815+ .defaultConfigurator ()
816+ .enableHostnameVerification ()
817+ .build ();
818+ } else {
819+ this .socketConf = SocketConfigurators .builder ()
820+ .add (this .socketConf )
821+ .enableHostnameVerification ()
822+ .build ();
823+ }
824+ }
825+
711826 public static String computeDefaultTlsProcotol (String [] supportedProtocols ) {
712827 if (supportedProtocols != null ) {
713828 for (String supportedProtocol : supportedProtocols ) {
@@ -791,11 +906,11 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IO
791906 if (this .nioParams .getNioExecutor () == null && this .nioParams .getThreadFactory () == null ) {
792907 this .nioParams .setThreadFactory (getThreadFactory ());
793908 }
794- this .frameHandlerFactory = new SocketChannelFrameHandlerFactory (connectionTimeout , nioParams , isSSL (), sslContext );
909+ this .frameHandlerFactory = new SocketChannelFrameHandlerFactory (connectionTimeout , nioParams , isSSL (), sslContext , connectionPostProcessor );
795910 }
796911 return this .frameHandlerFactory ;
797912 } else {
798- return new SocketFrameHandlerFactory (connectionTimeout , factory , socketConf , isSSL (), this .shutdownExecutor );
913+ return new SocketFrameHandlerFactory (connectionTimeout , factory , socketConf , isSSL (), this .shutdownExecutor , connectionPostProcessor );
799914 }
800915
801916 }
@@ -1439,4 +1554,15 @@ public void setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFil
14391554 public void setTopologyRecoveryRetryHandler (RetryHandler topologyRecoveryRetryHandler ) {
14401555 this .topologyRecoveryRetryHandler = topologyRecoveryRetryHandler ;
14411556 }
1557+
1558+ /**
1559+ * Hook to post-process the freshly open TCP connection.
1560+ *
1561+ * @param connectionPostProcessor
1562+ * @see #enableHostnameVerification()
1563+ * @see #enableHostnameVerification(HostnameVerifier)
1564+ */
1565+ public void setConnectionPostProcessor (ConnectionPostProcessor connectionPostProcessor ) {
1566+ this .connectionPostProcessor = connectionPostProcessor ;
1567+ }
14421568}
0 commit comments