diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index 20823f29c4..c44cec3f21 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -39,6 +39,7 @@ import org.springframework.context.annotation.Import; import org.springframework.retry.backoff.ExponentialBackOffPolicy; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; +import org.springframework.util.ReflectionUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}. @@ -87,6 +88,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 config) throws Exception { @@ -117,6 +123,16 @@ public class RabbitAutoConfiguration { factory.setKeyStorePassphrase(ssl.getKeyStorePassword()); factory.setTrustStore(ssl.getTrustStore()); factory.setTrustStorePassphrase(ssl.getTrustStorePassword()); + factory.setSkipServerCertificateValidation( + !ssl.isValidateServerCertificate()); + if (ssl.getVerifyHostname() != null) { + factory.setEnableHostnameVerification(ssl.getVerifyHostname()); + } + else { + if (CAN_ENABLE_HOSTNAME_VERIFICATION) { + factory.setEnableHostnameVerification(true); + } + } } if (config.getConnectionTimeout() != null) { factory.setConnectionTimeout(config.getConnectionTimeout()); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index e78387f2e5..e18c9d65b0 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -337,6 +337,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; } @@ -385,6 +396,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-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index 7c03a568b6..9866f52caf 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,10 @@ package org.springframework.boot.autoconfigure.amqp; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; import com.rabbitmq.client.Address; +import com.rabbitmq.client.NullTrustManager; import org.aopalliance.aop.Advice; import org.junit.After; import org.junit.Rule; @@ -53,6 +55,7 @@ import org.springframework.retry.backoff.ExponentialBackOffPolicy; import org.springframework.retry.interceptor.MethodInvocationRecoverer; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -411,6 +414,8 @@ public class RabbitAutoConfigurationTests { com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(); assertThat(rabbitConnectionFactory.getSocketFactory()) .as("SocketFactory must use SSL").isInstanceOf(SSLSocketFactory.class); + TrustManager trustManager = getTrustManager(rabbitConnectionFactory); + assertThat(trustManager).isNotInstanceOf(NullTrustManager.class); } @Test @@ -422,7 +427,38 @@ public class RabbitAutoConfigurationTests { "spring.rabbitmq.ssl.keyStore=foo", "spring.rabbitmq.ssl.keyStorePassword=secret", "spring.rabbitmq.ssl.trustStore=bar", - "spring.rabbitmq.ssl.trustStorePassword=secret"); + "spring.rabbitmq.ssl.trustStorePassword=secret", + "spring.rabbitmq.ssl.validateServerCertificate=false"); + getTargetConnectionFactory(); + } + + @Test + public void enableSslWithValidateServerCertificateFalse() throws Exception { + load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true", + "spring.rabbitmq.ssl.validateServerCertificate=false"); + com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(); + TrustManager trustManager = getTrustManager(rabbitConnectionFactory); + assertThat(trustManager).isInstanceOf(NullTrustManager.class); + } + + @Test + public void enableSslWithValidateServerCertificateDefault() throws Exception { + load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true"); + com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(); + TrustManager trustManager = getTrustManager(rabbitConnectionFactory); + assertThat(trustManager).isNotInstanceOf(NullTrustManager.class); + } + + private TrustManager getTrustManager( + com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory) { + Object sslContext = ReflectionTestUtils.getField(rabbitConnectionFactory, + "sslContext"); + 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() { diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 98d125c859..6a10e69df8 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -140,6 +140,7 @@ 2.1.6 9.4.1212.jre7 4.1.4 + 4.0.3 2.0.8.RELEASE 2.0.7.RELEASE 2.53.1 @@ -152,7 +153,7 @@ 5.5.5 1.0-groovy-2.4 4.3.18.RELEASE - 1.7.9.RELEASE + 1.7.10.BUILD-SNAPSHOT 1.2.6.RELEASE 3.0.9.RELEASE Ingalls-SR14 @@ -730,6 +731,11 @@ + + com.rabbitmq + amqp-client + ${rabbit-amqp-client.version} + com.samskivert jmustache @@ -3263,4 +3269,4 @@ integration-test - \ No newline at end of file + diff --git a/spring-boot-samples/spring-boot-sample-amqp/pom.xml b/spring-boot-samples/spring-boot-sample-amqp/pom.xml index 94c200de2b..3b6d1ba42f 100644 --- a/spring-boot-samples/spring-boot-sample-amqp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-amqp/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 @@ -17,6 +19,7 @@ ${basedir}/../.. + 4.8.0