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 0ea5a3e4e3f..2b849b50663 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 @@ -113,8 +113,14 @@ public class RabbitAutoConfiguration { if (ssl.getAlgorithm() != null) { factory.setSslAlgorithm(ssl.getAlgorithm()); } + if (ssl.getKeyStoreType() != null) { + factory.setKeyStoreType(ssl.getKeyStoreType()); + } factory.setKeyStore(ssl.getKeyStore()); factory.setKeyStorePassphrase(ssl.getKeyStorePassword()); + if (ssl.getTrustStoreType() != null) { + factory.setTrustStoreType(ssl.getTrustStoreType()); + } factory.setTrustStore(ssl.getTrustStore()); factory.setTrustStorePassphrase(ssl.getTrustStorePassword()); } 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 66e7f483be5..2b57df1cd15 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 @@ -314,6 +314,11 @@ public class RabbitProperties { */ private String keyStore; + /** + * Set the key store type (jks, pkcs12, etc). + */ + private String keyStoreType; + /** * Password used to access the key store. */ @@ -324,6 +329,11 @@ public class RabbitProperties { */ private String trustStore; + /** + * Set the trust store type (jks, pkcs12, etc). + */ + private String trustStoreType; + /** * Password used to access the trust store. */ @@ -351,6 +361,14 @@ public class RabbitProperties { this.keyStore = keyStore; } + public String getKeyStoreType() { + return this.keyStoreType; + } + + public void setKeyStoreType(String keyStoreType) { + this.keyStoreType = keyStoreType; + } + public String getKeyStorePassword() { return this.keyStorePassword; } @@ -367,6 +385,14 @@ public class RabbitProperties { this.trustStore = trustStore; } + public String getTrustStoreType() { + return this.trustStoreType; + } + + public void setTrustStoreType(String trustStoreType) { + this.trustStoreType = trustStoreType; + } + public String getTrustStorePassword() { return this.trustStorePassword; } 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 9132448dc81..782c426b280 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 @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.amqp; +import java.security.NoSuchAlgorithmException; + import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; @@ -540,21 +542,80 @@ public class RabbitAutoConfigurationTests { @Test // Make sure that we at least attempt to load the store - public void enableSslWithExtraConfig() { - this.contextRunner.withUserConfiguration(TestConfiguration.class) + public void enableSslWithNonexistingKeystoreShouldFail() { + this.contextRunner + .withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.rabbitmq.ssl.enabled:true", "spring.rabbitmq.ssl.keyStore=foo", - "spring.rabbitmq.ssl.keyStorePassword=secret", + "spring.rabbitmq.ssl.keyStorePassword=secret") + .run(context -> { + assertThat(context).hasFailed(); + assertThat(context).getFailure().hasMessageContaining("foo"); + assertThat(context).getFailure().hasMessageContaining("does not exist"); + }); + } + + @Test + // Make sure that we at least attempt to load the store + public void enableSslWithNonexistingTruststoreShouldFail() { + this.contextRunner + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues( + "spring.rabbitmq.ssl.enabled:true", "spring.rabbitmq.ssl.trustStore=bar", "spring.rabbitmq.ssl.trustStorePassword=secret") .run((context) -> { assertThat(context).hasFailed(); - assertThat(context).getFailure().hasMessageContaining("foo"); - assertThat(context).getFailure() - .hasMessageContaining("does not exist"); + assertThat(context).getFailure().hasMessageContaining("bar"); + assertThat(context).getFailure().hasMessageContaining("does not exist"); }); } + @Test + public void enableSslWithInvalidKeystoreTypeShouldFail() throws Exception { + this.contextRunner + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues( + "spring.rabbitmq.ssl.enabled:true", + "spring.rabbitmq.ssl.keyStore=foo", + "spring.rabbitmq.ssl.keyStoreType=fooType") + .run(context -> { + assertThat(context).hasFailed(); + assertThat(context).getFailure().hasMessageContaining("fooType"); + assertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class); + }); + } + + @Test + public void enableSslWithInvalidTruststoreTypeShouldFail() throws Exception { + this.contextRunner + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues( + "spring.rabbitmq.ssl.enabled:true", + "spring.rabbitmq.ssl.trustStore=bar", + "spring.rabbitmq.ssl.trustStoreType=barType") + .run(context -> { + assertThat(context).hasFailed(); + assertThat(context).getFailure().hasMessageContaining("barType"); + assertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class); + }); + } + + @Test + public void enableSslWithKeystoreTypeAndTrustStoreTypeShouldWork() throws Exception { + this.contextRunner + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues( + "spring.rabbitmq.ssl.enabled:true", + "spring.rabbitmq.ssl.keyStore=/org/springframework/boot/autoconfigure/amqp/test.jks", + "spring.rabbitmq.ssl.keyStoreType=jks", + "spring.rabbitmq.ssl.keyStorePassword=secret", + "spring.rabbitmq.ssl.trustStore=/org/springframework/boot/autoconfigure/amqp/test.jks", + "spring.rabbitmq.ssl.trustStoreType=jks", + "spring.rabbitmq.ssl.trustStorePassword=secret") + .run(context -> assertThat(context).hasNotFailed()); + } + private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory( AssertableApplicationContext context) { CachingConnectionFactory connectionFactory = context diff --git a/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/amqp/test.jks b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/amqp/test.jks new file mode 100644 index 00000000000..8413be81095 Binary files /dev/null and b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/amqp/test.jks differ diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index a23ce5c6060..3e5e7acf3cb 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1051,8 +1051,10 @@ content into your application; rather pick only the properties that you need. spring.rabbitmq.requested-heartbeat= # Requested heartbeat timeout, in seconds; zero for none. spring.rabbitmq.ssl.enabled=false # Enable SSL support. spring.rabbitmq.ssl.key-store= # Path to the key store that holds the SSL certificate. + spring.rabbitmq.ssl.key-store-type= # Type of key store (jks, pkcs12,..). Defaults to pkcs12 if not set spring.rabbitmq.ssl.key-store-password= # Password used to access the key store. spring.rabbitmq.ssl.trust-store= # Trust store that holds SSL certificates. + spring.rabbitmq.ssl.trust-store-type= # Type of trust store (jks, pkcs12,..). Defaults to jks if not set spring.rabbitmq.ssl.trust-store-password= # Password used to access the trust store. spring.rabbitmq.ssl.algorithm= # SSL algorithm to use. By default configure by the rabbit client library. spring.rabbitmq.template.mandatory=false # Enable mandatory messages.