From aff4d0aefcdb99726fd739abf3b9bb96df97b0fa Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 28 Aug 2018 13:05:55 -0400 Subject: [PATCH] AMQP-830 Enable Hostname Verification by default JIRA: https://jira.spring.io/browse/AMQP-830 --- .../RabbitConnectionFactoryBean.java | 121 ++++++++++++++++-- src/reference/asciidoc/whats-new.adoc | 6 + 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java index b4f18a41..2e59cd28 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/connection/RabbitConnectionFactoryBean.java @@ -16,11 +16,11 @@ package org.springframework.amqp.rabbit.connection; +import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.KeyStore; -import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; @@ -28,8 +28,10 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -42,6 +44,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.ReflectionUtils.MethodCallback; +import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.util.StringUtils; import com.rabbitmq.client.ConnectionFactory; @@ -75,6 +81,37 @@ import com.rabbitmq.client.impl.nio.NioParams; */ public class RabbitConnectionFactoryBean extends AbstractFactoryBean { + public static final Method enableHostnameVerificationNoArgMethod; + + public static final Method enableHostnameVerificationOneArgMethod; + + static { + final AtomicReference method1 = new AtomicReference(); + final AtomicReference method2 = new AtomicReference(); + ReflectionUtils.doWithMethods(ConnectionFactory.class, new MethodCallback() { + + @Override + public void doWith(Method m) throws IllegalArgumentException, IllegalAccessException { + if (m.getParameterTypes().length == 0) { + method1.set(m); + } + else if (m.getParameterTypes().length == 1 && m.getParameterTypes()[0].equals(HostnameVerifier.class)) { + method2.set(m); + } + } + + }, new MethodFilter() { + + @Override + public boolean matches(Method m) { + return m.getName().equals("enableHostnameVerification"); + } + + }); + enableHostnameVerificationNoArgMethod = method1.get(); + enableHostnameVerificationOneArgMethod = method2.get(); + } + private final Log logger = LogFactory.getLog(getClass()); private static final String KEY_STORE = "keyStore"; @@ -103,30 +140,34 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean + * This enables hostname verification regardless of the IO mode used (blocking or + * non-blocking IO). + *

+ * If using Java 7 or more, the hostname verification will be + * performed by Java, as part of the TLS handshake. + *

+ * If using Java 6, the hostname verification will be handled after + * the TLS handshake, using the {@link HostnameVerifier} from the Commons HttpClient + * project. This requires to add Commons HttpClient and its dependencies to the + * classpath. To use a custom {@link HostnameVerifier}, use + * {@link #setHostnameVerifier(HostnameVerifier)}. Requires + * amqp-client 4.8.0 or later. + * @param enable true to enable. + * @since 1.7.10 + * @see #setHostnameVerifier(HostnameVerifier) + */ + public void setEnableHostnameVerification(boolean enable) { + Assert.notNull(enableHostnameVerificationNoArgMethod, + "Host name verification requires amqp-client 4.8.0 or later"); + this.enableHostnameVerification = enable; + } + + /** + * Set a custom {@link HostnameVerifier} for use with + * {@link #setEnableHostnameVerification(boolean)}. + * @param hostnameVerifier the verifier. + * @see #setEnableHostnameVerification(boolean) + * @deprecated only used with Java 6 + */ + @Deprecated + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + Assert.notNull(enableHostnameVerificationOneArgMethod, + "Host name verification requires amqp-client 4.8.0 or later, " + + "when using 5.8.0 or later, a custom verifier is not required"); + this.hostnameVerifier = hostnameVerifier; + } + @Override public Class getObjectType() { return ConnectionFactory.class; @@ -674,6 +755,7 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean> for more information. Message requeue on transaction rollback can now be configured to be consistent, regardless of whether or not a transaction manager is configured. See <> for more information. +===== Connection Factory Bean Changes + +The `RabbitConnectionFactoryBean` now provides an `enabaleHostnameVerification` property; set it to `true` to enable host name verification. +Also `setHostnameVerifier` is provided for when using Java 6; see the connection factory javadocs for more information. +Host name verification requires overriding the `amqp-client` to 4.8.0 or later. + ==== Earlier Releases See <> for changes in previous versions.