Skip to content

Commit a50686b

Browse files
committed
Surface additional rabbit SSL factory properties
Add `validate-server-certificate` and `verify-hostname` properties to `spring.rabbitmq.ssl` to allow additional SSL configuration. Closes gh-14259
1 parent ca7f961 commit a50686b

File tree

5 files changed

+93
-5
lines changed

5 files changed

+93
-5
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
4040
import org.springframework.retry.policy.SimpleRetryPolicy;
4141
import org.springframework.retry.support.RetryTemplate;
42+
import org.springframework.util.ReflectionUtils;
4243

4344
/**
4445
* {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}.
@@ -87,6 +88,11 @@ public class RabbitAutoConfiguration {
8788
@ConditionalOnMissingBean(ConnectionFactory.class)
8889
protected static class RabbitConnectionFactoryCreator {
8990

91+
// Only available in rabbitmq-java-client 5.4.0 +
92+
private static final boolean CAN_ENABLE_HOSTNAME_VERIFICATION = ReflectionUtils
93+
.findMethod(com.rabbitmq.client.ConnectionFactory.class,
94+
"enableHostnameVerification") != null;
95+
9096
@Bean
9197
public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config)
9298
throws Exception {
@@ -117,6 +123,16 @@ public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config)
117123
factory.setKeyStorePassphrase(ssl.getKeyStorePassword());
118124
factory.setTrustStore(ssl.getTrustStore());
119125
factory.setTrustStorePassphrase(ssl.getTrustStorePassword());
126+
factory.setSkipServerCertificateValidation(
127+
!ssl.isValidateServerCertificate());
128+
if (ssl.getVerifyHostname() != null) {
129+
factory.setEnableHostnameVerification(ssl.getVerifyHostname());
130+
}
131+
else {
132+
if (CAN_ENABLE_HOSTNAME_VERIFICATION) {
133+
factory.setEnableHostnameVerification(true);
134+
}
135+
}
120136
}
121137
if (config.getConnectionTimeout() != null) {
122138
factory.setConnectionTimeout(config.getConnectionTimeout());

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,17 @@ public static class Ssl {
337337
*/
338338
private String algorithm;
339339

340+
/**
341+
* Whether to enable server side certificate validation.
342+
*/
343+
private boolean validateServerCertificate = true;
344+
345+
/**
346+
* Whether to enable hostname verification. Requires AMQP client 4.8 or above and
347+
* defaults to true when a suitable client version is used.
348+
*/
349+
private Boolean verifyHostname;
350+
340351
public boolean isEnabled() {
341352
return this.enabled;
342353
}
@@ -385,6 +396,22 @@ public void setAlgorithm(String sslAlgorithm) {
385396
this.algorithm = sslAlgorithm;
386397
}
387398

399+
public boolean isValidateServerCertificate() {
400+
return this.validateServerCertificate;
401+
}
402+
403+
public void setValidateServerCertificate(boolean validateServerCertificate) {
404+
this.validateServerCertificate = validateServerCertificate;
405+
}
406+
407+
public Boolean getVerifyHostname() {
408+
return this.verifyHostname;
409+
}
410+
411+
public void setVerifyHostname(Boolean verifyHostname) {
412+
this.verifyHostname = verifyHostname;
413+
}
414+
388415
}
389416

390417
public static class Cache {

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,8 +18,10 @@
1818

1919
import javax.net.SocketFactory;
2020
import javax.net.ssl.SSLSocketFactory;
21+
import javax.net.ssl.TrustManager;
2122

2223
import com.rabbitmq.client.Address;
24+
import com.rabbitmq.client.NullTrustManager;
2325
import org.aopalliance.aop.Advice;
2426
import org.junit.After;
2527
import org.junit.Rule;
@@ -53,6 +55,7 @@
5355
import org.springframework.retry.interceptor.MethodInvocationRecoverer;
5456
import org.springframework.retry.policy.SimpleRetryPolicy;
5557
import org.springframework.retry.support.RetryTemplate;
58+
import org.springframework.test.util.ReflectionTestUtils;
5659

5760
import static org.assertj.core.api.Assertions.assertThat;
5861
import static org.mockito.Mockito.mock;
@@ -411,6 +414,8 @@ public void enableSsl() {
411414
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
412415
assertThat(rabbitConnectionFactory.getSocketFactory())
413416
.as("SocketFactory must use SSL").isInstanceOf(SSLSocketFactory.class);
417+
TrustManager trustManager = getTrustManager(rabbitConnectionFactory);
418+
assertThat(trustManager).isNotInstanceOf(NullTrustManager.class);
414419
}
415420

416421
@Test
@@ -422,7 +427,38 @@ public void enableSslWithExtraConfig() {
422427
"spring.rabbitmq.ssl.keyStore=foo",
423428
"spring.rabbitmq.ssl.keyStorePassword=secret",
424429
"spring.rabbitmq.ssl.trustStore=bar",
425-
"spring.rabbitmq.ssl.trustStorePassword=secret");
430+
"spring.rabbitmq.ssl.trustStorePassword=secret",
431+
"spring.rabbitmq.ssl.validateServerCertificate=false");
432+
getTargetConnectionFactory();
433+
}
434+
435+
@Test
436+
public void enableSslWithValidateServerCertificateFalse() throws Exception {
437+
load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true",
438+
"spring.rabbitmq.ssl.validateServerCertificate=false");
439+
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
440+
TrustManager trustManager = getTrustManager(rabbitConnectionFactory);
441+
assertThat(trustManager).isInstanceOf(NullTrustManager.class);
442+
}
443+
444+
@Test
445+
public void enableSslWithValidateServerCertificateDefault() throws Exception {
446+
load(TestConfiguration.class, "spring.rabbitmq.ssl.enabled:true");
447+
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory();
448+
TrustManager trustManager = getTrustManager(rabbitConnectionFactory);
449+
assertThat(trustManager).isNotInstanceOf(NullTrustManager.class);
450+
}
451+
452+
private TrustManager getTrustManager(
453+
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory) {
454+
Object sslContext = ReflectionTestUtils.getField(rabbitConnectionFactory,
455+
"sslContext");
456+
Object spi = ReflectionTestUtils.getField(sslContext, "contextSpi");
457+
Object trustManager = ReflectionTestUtils.getField(spi, "trustManager");
458+
while (trustManager.getClass().getName().endsWith("Wrapper")) {
459+
trustManager = ReflectionTestUtils.getField(trustManager, "tm");
460+
}
461+
return (TrustManager) trustManager;
426462
}
427463

428464
private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory() {

spring-boot-dependencies/pom.xml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
<neo4j-ogm.version>2.1.6</neo4j-ogm.version>
141141
<postgresql.version>9.4.1212.jre7</postgresql.version>
142142
<querydsl.version>4.1.4</querydsl.version>
143+
<rabbit-amqp-client.version>4.0.3</rabbit-amqp-client.version>
143144
<reactor.version>2.0.8.RELEASE</reactor.version>
144145
<reactor-spring.version>2.0.7.RELEASE</reactor-spring.version>
145146
<selenium.version>2.53.1</selenium.version>
@@ -152,7 +153,7 @@
152153
<solr.version>5.5.5</solr.version>
153154
<spock.version>1.0-groovy-2.4</spock.version>
154155
<spring.version>4.3.18.RELEASE</spring.version>
155-
<spring-amqp.version>1.7.9.RELEASE</spring-amqp.version>
156+
<spring-amqp.version>1.7.10.BUILD-SNAPSHOT</spring-amqp.version>
156157
<spring-cloud-connectors.version>1.2.6.RELEASE</spring-cloud-connectors.version>
157158
<spring-batch.version>3.0.9.RELEASE</spring-batch.version>
158159
<spring-data-releasetrain.version>Ingalls-SR14</spring-data-releasetrain.version>
@@ -730,6 +731,11 @@
730731
</exclusion>
731732
</exclusions>
732733
</dependency>
734+
<dependency>
735+
<groupId>com.rabbitmq</groupId>
736+
<artifactId>amqp-client</artifactId>
737+
<version>${rabbit-amqp-client.version}</version>
738+
</dependency>
733739
<dependency>
734740
<groupId>com.samskivert</groupId>
735741
<artifactId>jmustache</artifactId>
@@ -3263,4 +3269,4 @@
32633269
<id>integration-test</id>
32643270
</profile>
32653271
</profiles>
3266-
</project>
3272+
</project>

spring-boot-samples/spring-boot-sample-amqp/pom.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
35
<modelVersion>4.0.0</modelVersion>
46
<parent>
57
<!-- Your own application should inherit from spring-boot-starter-parent -->
@@ -17,6 +19,7 @@
1719
</organization>
1820
<properties>
1921
<main.basedir>${basedir}/../..</main.basedir>
22+
<rabbit-amqp-client.version>4.8.0</rabbit-amqp-client.version>
2023
</properties>
2124
<dependencies>
2225
<!-- Compile -->

0 commit comments

Comments
 (0)