Apply verify-hostname consistently

Closes gh-50168
This commit is contained in:
Andy Wilkinson
2026-04-23 08:42:51 +01:00
parent 2c2ffe51c4
commit e4febe2015
3 changed files with 77 additions and 22 deletions
@@ -132,25 +132,15 @@ public class RabbitConnectionFactoryBeanConfigurer {
.to(factory::setRequestedHeartbeat);
map.from(this.rabbitProperties::getRequestedChannelMax).to(factory::setRequestedChannelMax);
SslBundle sslBundle = this.connectionDetails.getSslBundle();
if (sslBundle != null) {
applySslBundle(factory, sslBundle);
}
else {
RabbitProperties.Ssl ssl = this.rabbitProperties.getSsl();
if (ssl.determineEnabled()) {
factory.setUseSSL(true);
map.from(ssl::getAlgorithm).whenNonNull().to(factory::setSslAlgorithm);
map.from(ssl::getKeyStoreType).to(factory::setKeyStoreType);
map.from(ssl::getKeyStore).to(factory::setKeyStore);
map.from(ssl::getKeyStorePassword).to(factory::setKeyStorePassphrase);
map.from(ssl::getKeyStoreAlgorithm).whenNonNull().to(factory::setKeyStoreAlgorithm);
map.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);
map.from(ssl::getTrustStore).to(factory::setTrustStore);
map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);
map.from(ssl::getTrustStoreAlgorithm).whenNonNull().to(factory::setTrustStoreAlgorithm);
map.from(ssl::isValidateServerCertificate)
.to((validate) -> factory.setSkipServerCertificateValidation(!validate));
map.from(ssl::isVerifyHostname).to(factory::setEnableHostnameVerification);
RabbitProperties.Ssl ssl = this.rabbitProperties.getSsl();
if (sslBundle != null || ssl.determineEnabled()) {
factory.setUseSSL(true);
map.from(ssl::isVerifyHostname).to(factory::setEnableHostnameVerification);
if (sslBundle != null) {
applySslBundle(factory, sslBundle);
}
else {
applySslProperties(factory, map, ssl);
}
}
map.from(this.rabbitProperties::getConnectionTimeout)
@@ -169,11 +159,24 @@ public class RabbitConnectionFactoryBeanConfigurer {
.to(factory::setMaxInboundMessageBodySize);
}
private static void applySslBundle(RabbitConnectionFactoryBean factory, SslBundle bundle) {
factory.setUseSSL(true);
private void applySslBundle(RabbitConnectionFactoryBean factory, SslBundle bundle) {
if (factory instanceof SslBundleRabbitConnectionFactoryBean sslFactory) {
sslFactory.setSslBundle(bundle);
}
}
private void applySslProperties(RabbitConnectionFactoryBean factory, PropertyMapper map, RabbitProperties.Ssl ssl) {
map.from(ssl::getAlgorithm).whenNonNull().to(factory::setSslAlgorithm);
map.from(ssl::getKeyStoreType).to(factory::setKeyStoreType);
map.from(ssl::getKeyStore).to(factory::setKeyStore);
map.from(ssl::getKeyStorePassword).to(factory::setKeyStorePassphrase);
map.from(ssl::getKeyStoreAlgorithm).whenNonNull().to(factory::setKeyStoreAlgorithm);
map.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);
map.from(ssl::getTrustStore).to(factory::setTrustStore);
map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);
map.from(ssl::getTrustStoreAlgorithm).whenNonNull().to(factory::setTrustStoreAlgorithm);
map.from(ssl::isValidateServerCertificate)
.to((validate) -> factory.setSkipServerCertificateValidation(!validate));
}
}
@@ -29,7 +29,7 @@ class SslBundleRabbitConnectionFactoryBean extends RabbitConnectionFactoryBean {
private SslBundle sslBundle;
private boolean enableHostnameVerification;
private boolean enableHostnameVerification = true;
@Override
protected void setUpSSL() {
@@ -16,17 +16,21 @@
package org.springframework.boot.autoconfigure.amqp;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocketFactory;
import com.rabbitmq.client.Address;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.JDKSaslConfig;
import com.rabbitmq.client.SslEngineConfigurator;
import com.rabbitmq.client.impl.CredentialsProvider;
import com.rabbitmq.client.impl.CredentialsRefreshService;
import com.rabbitmq.client.impl.DefaultCredentialsProvider;
@@ -38,6 +42,7 @@ import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.springframework.amqp.core.AcknowledgeMode;
@@ -843,6 +848,20 @@ class RabbitAutoConfigurationTests {
assertThat(rabbitConnectionFactory.isSSL()).isTrue();
assertThat(rabbitConnectionFactory.getSocketFactory()).as("SocketFactory must use SSL")
.isInstanceOf(SSLSocketFactory.class);
assertThatHostnameVerificationIsEnabled(rabbitConnectionFactory);
});
}
@Test
void enableSslWithoutHostnameVerification() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.rabbitmq.ssl.enabled:true", "spring.rabbitmq.ssl.verify-hostname:false")
.run((context) -> {
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);
assertThat(rabbitConnectionFactory.isSSL()).isTrue();
assertThat(rabbitConnectionFactory.getSocketFactory()).as("SocketFactory must use SSL")
.isInstanceOf(SSLSocketFactory.class);
assertThatHostnameVerificationIsDisabled(rabbitConnectionFactory);
});
}
@@ -915,6 +934,20 @@ class RabbitAutoConfigurationTests {
.run((context) -> {
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);
assertThat(rabbitConnectionFactory.isSSL()).isTrue();
assertThatHostnameVerificationIsEnabled(rabbitConnectionFactory);
});
}
@Test
void enableSslWithBundleAndWithoutHostnameVerification() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.rabbitmq.ssl.bundle=test-bundle", "spring.rabbitmq.ssl.verify-hostname=false",
"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:org/springframework/boot/autoconfigure/amqp/test.jks",
"spring.ssl.bundle.jks.test-bundle.keystore.password=secret")
.run((context) -> {
com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);
assertThat(rabbitConnectionFactory.isSSL()).isTrue();
assertThatHostnameVerificationIsDisabled(rabbitConnectionFactory);
});
}
@@ -1078,6 +1111,25 @@ class RabbitAutoConfigurationTests {
.configure(any(DirectMessageListenerContainer.class)));
}
private void assertThatHostnameVerificationIsEnabled(com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory)
throws IOException {
SslEngineConfigurator sslEngineConfigurator = rabbitConnectionFactory.getNioParams().getSslEngineConfigurator();
SSLEngine engine = mock(SSLEngine.class);
sslEngineConfigurator.configure(engine);
ArgumentCaptor<SSLParameters> sslParametersCaptor = ArgumentCaptor.forClass(SSLParameters.class);
then(engine).should().setSSLParameters(sslParametersCaptor.capture());
SSLParameters sslParameters = sslParametersCaptor.getValue();
assertThat(sslParameters.getEndpointIdentificationAlgorithm()).isEqualTo("HTTPS");
}
private void assertThatHostnameVerificationIsDisabled(com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory)
throws IOException {
SslEngineConfigurator sslEngineConfigurator = rabbitConnectionFactory.getNioParams().getSslEngineConfigurator();
SSLEngine engine = mock(SSLEngine.class);
sslEngineConfigurator.configure(engine);
then(engine).shouldHaveNoMoreInteractions();
}
private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory(AssertableApplicationContext context) {
CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
return connectionFactory.getRabbitConnectionFactory();