diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
index c9573b4fee..ff3ec81253 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.amqp;
import java.time.Duration;
import java.util.List;
+import java.util.Objects;
import com.rabbitmq.client.Channel;
@@ -41,6 +42,7 @@ import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import org.springframework.util.ReflectionUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}.
@@ -91,6 +93,11 @@ public class RabbitAutoConfiguration {
@ConditionalOnMissingBean(ConnectionFactory.class)
protected static class RabbitConnectionFactoryCreator {
+ // Only available in rabbitmq-java-client 5.4.0 +
+ private static final boolean CAN_ENABLE_HOSTNAME_VERIFICATION = ReflectionUtils
+ .findMethod(com.rabbitmq.client.ConnectionFactory.class,
+ "enableHostnameVerification") != null;
+
@Bean
public CachingConnectionFactory rabbitConnectionFactory(
RabbitProperties properties,
@@ -140,6 +147,13 @@ public class RabbitAutoConfiguration {
map.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);
map.from(ssl::getTrustStore).to(factory::setTrustStore);
map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);
+ map.from(ssl::isValidateServerCertificate).to((validate) -> factory
+ .setSkipServerCertificateValidation(!validate));
+ map.from(ssl::getVerifyHostname).when(Objects::nonNull)
+ .to(factory::setEnableHostnameVerification);
+ if (ssl.getVerifyHostname() == null && CAN_ENABLE_HOSTNAME_VERIFICATION) {
+ factory.setEnableHostnameVerification(true);
+ }
}
map.from(properties::getConnectionTimeout).whenNonNull()
.asInt(Duration::toMillis).to(factory::setConnectionTimeout);
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java
index 02292ebecc..44a9157f3a 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java
@@ -350,6 +350,17 @@ public class RabbitProperties {
*/
private String algorithm;
+ /**
+ * Whether to enable server side certificate validation.
+ */
+ private boolean validateServerCertificate = true;
+
+ /**
+ * Whether to enable hostname verification. Requires AMQP client 4.8 or above and
+ * defaults to true when a suitable client version is used.
+ */
+ private Boolean verifyHostname;
+
public boolean isEnabled() {
return this.enabled;
}
@@ -414,6 +425,22 @@ public class RabbitProperties {
this.algorithm = sslAlgorithm;
}
+ public boolean isValidateServerCertificate() {
+ return this.validateServerCertificate;
+ }
+
+ public void setValidateServerCertificate(boolean validateServerCertificate) {
+ this.validateServerCertificate = validateServerCertificate;
+ }
+
+ public Boolean getVerifyHostname() {
+ return this.verifyHostname;
+ }
+
+ public void setVerifyHostname(Boolean verifyHostname) {
+ this.verifyHostname = verifyHostname;
+ }
+
}
public static class Cache {
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java
index 37ef790aab..73b66d3ede 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java
@@ -19,10 +19,14 @@ package org.springframework.boot.autoconfigure.amqp;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
import com.rabbitmq.client.Address;
import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.SslContextFactory;
+import com.rabbitmq.client.TrustEverythingTrustManager;
import org.aopalliance.aop.Advice;
import org.junit.Rule;
import org.junit.Test;
@@ -764,6 +768,45 @@ public class RabbitAutoConfigurationTests {
.run((context) -> assertThat(context).hasNotFailed());
}
+ @Test
+ public void enableSslWithValidateServerCertificateFalse() throws Exception {
+ this.contextRunner.withUserConfiguration(TestConfiguration.class)
+ .withPropertyValues("spring.rabbitmq.ssl.enabled:true",
+ "spring.rabbitmq.ssl.validateServerCertificate=false")
+ .run((context) -> {
+ com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(
+ context);
+ TrustManager trustManager = getTrustManager(rabbitConnectionFactory);
+ assertThat(trustManager)
+ .isInstanceOf(TrustEverythingTrustManager.class);
+ });
+ }
+
+ @Test
+ public void enableSslWithValidateServerCertificateDefault() throws Exception {
+ this.contextRunner.withUserConfiguration(TestConfiguration.class)
+ .withPropertyValues("spring.rabbitmq.ssl.enabled:true").run((context) -> {
+ com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(
+ context);
+ TrustManager trustManager = getTrustManager(rabbitConnectionFactory);
+ assertThat(trustManager)
+ .isNotInstanceOf(TrustEverythingTrustManager.class);
+ });
+ }
+
+ private TrustManager getTrustManager(
+ com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory) {
+ SslContextFactory sslContextFactory = (SslContextFactory) ReflectionTestUtils
+ .getField(rabbitConnectionFactory, "sslContextFactory");
+ SSLContext sslContext = sslContextFactory.create("connection");
+ Object spi = ReflectionTestUtils.getField(sslContext, "contextSpi");
+ Object trustManager = ReflectionTestUtils.getField(spi, "trustManager");
+ while (trustManager.getClass().getName().endsWith("Wrapper")) {
+ trustManager = ReflectionTestUtils.getField(trustManager, "tm");
+ }
+ return (TrustManager) trustManager;
+ }
+
private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory(
AssertableApplicationContext context) {
CachingConnectionFactory connectionFactory = context
diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml
index 06a47ea13c..5a9c101c4e 100644
--- a/spring-boot-project/spring-boot-dependencies/pom.xml
+++ b/spring-boot-project/spring-boot-dependencies/pom.xml
@@ -156,7 +156,7 @@
1.23
7.4.0
5.1.0.BUILD-SNAPSHOT
- 2.1.0.M2
+ 2.1.0.BUILD-SNAPSHOT
4.1.0.M3
2.0.2.RELEASE
Lovelace-RC2
diff --git a/spring-boot-samples/spring-boot-sample-amqp/pom.xml b/spring-boot-samples/spring-boot-sample-amqp/pom.xml
index 9cd849c0d4..c6a66a6100 100644
--- a/spring-boot-samples/spring-boot-sample-amqp/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-amqp/pom.xml
@@ -1,5 +1,6 @@
-
4.0.0
@@ -13,6 +14,7 @@
Spring Boot AMQP Sample
${basedir}/../..
+ 5.4.0