Skip to content

Commit e22083a

Browse files
committed
Enable hostname verification for SSL connections to Cassandra
Closes gh-50171
1 parent 5ceb1a2 commit e22083a

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public CqlSessionBuilder cassandraSessionBuilder(DriverConfigLoader driverConfig
115115
ObjectProvider<CqlSessionBuilderCustomizer> builderCustomizers) {
116116
CqlSessionBuilder builder = CqlSession.builder().withConfigLoader(driverConfigLoader);
117117
configureAuthentication(builder, connectionDetails);
118-
configureSsl(builder, connectionDetails);
118+
configureSsl(builder, connectionDetails, this.properties.getSsl().isVerifyHostname());
119119
builder.withKeyspace(this.properties.getKeyspaceName());
120120
builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
121121
return builder;
@@ -128,15 +128,16 @@ private void configureAuthentication(CqlSessionBuilder builder, CassandraConnect
128128
}
129129
}
130130

131-
private void configureSsl(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails) {
131+
private void configureSsl(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails,
132+
boolean verifyHostname) {
132133
SslBundle sslBundle = connectionDetails.getSslBundle();
133134
if (sslBundle == null) {
134135
return;
135136
}
136137
SslOptions options = sslBundle.getOptions();
137138
Assert.state(options.getEnabledProtocols() == null, "SSL protocol options cannot be specified with Cassandra");
138-
builder
139-
.withSslEngineFactory(new ProgrammaticSslEngineFactory(sslBundle.createSslContext(), options.getCiphers()));
139+
builder.withSslEngineFactory(
140+
new ProgrammaticSslEngineFactory(sslBundle.createSslContext(), options.getCiphers(), verifyHostname));
140141
}
141142

142143
@Bean(destroyMethod = "")

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraProperties.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ public static class Ssl {
225225
*/
226226
private Boolean enabled;
227227

228+
/**
229+
* Whether to perform hostname verification.
230+
*/
231+
private boolean verifyHostname = true;
232+
228233
/**
229234
* SSL bundle name.
230235
*/
@@ -246,6 +251,14 @@ public void setBundle(String bundle) {
246251
this.bundle = bundle;
247252
}
248253

254+
public boolean isVerifyHostname() {
255+
return this.verifyHostname;
256+
}
257+
258+
public void setVerifyHostname(boolean verifyHostname) {
259+
this.verifyHostname = verifyHostname;
260+
}
261+
249262
}
250263

251264
public static class Connection {

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfigurationTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,23 @@ void cqlSessionBuilderWithSslEnabled() {
8686
this.contextRunner.withPropertyValues("spring.cassandra.ssl.enabled=true").run((context) -> {
8787
CqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);
8888
assertThat(builder).hasFieldOrPropertyWithValue("programmaticSslFactory", true);
89+
assertThat(builder).extracting("programmaticArgumentsBuilder.sslEngineFactory")
90+
.hasFieldOrPropertyWithValue("requireHostnameValidation", true);
8991
});
9092
}
9193

94+
@Test
95+
void cqlSessionBuilderWithSslEnabledAndVerifyHostnameDisabled() {
96+
this.contextRunner
97+
.withPropertyValues("spring.cassandra.ssl.enabled=true", "spring.cassandra.ssl.verify-hostname=false")
98+
.run((context) -> {
99+
CqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);
100+
assertThat(builder).hasFieldOrPropertyWithValue("programmaticSslFactory", true);
101+
assertThat(builder).extracting("programmaticArgumentsBuilder.sslEngineFactory")
102+
.hasFieldOrPropertyWithValue("requireHostnameValidation", false);
103+
});
104+
}
105+
92106
@Test
93107
@WithPackageResources("test.jks")
94108
void cqlSessionBuilderWithSslBundle() {
@@ -100,6 +114,24 @@ void cqlSessionBuilderWithSslBundle() {
100114
.run((context) -> {
101115
CqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);
102116
assertThat(builder).hasFieldOrPropertyWithValue("programmaticSslFactory", true);
117+
assertThat(builder).extracting("programmaticArgumentsBuilder.sslEngineFactory")
118+
.hasFieldOrPropertyWithValue("requireHostnameValidation", true);
119+
});
120+
}
121+
122+
@Test
123+
@WithPackageResources("test.jks")
124+
void cqlSessionBuilderWithSslBundleAndVerifyHostnameDisabled() {
125+
this.contextRunner
126+
.withPropertyValues("spring.cassandra.ssl.bundle=test-bundle", "spring.cassandra.ssl.verify-hostname=false",
127+
"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks",
128+
"spring.ssl.bundle.jks.test-bundle.keystore.password=secret",
129+
"spring.ssl.bundle.jks.test-bundle.key.password=password")
130+
.run((context) -> {
131+
CqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);
132+
assertThat(builder).hasFieldOrPropertyWithValue("programmaticSslFactory", true);
133+
assertThat(builder).extracting("programmaticArgumentsBuilder.sslEngineFactory")
134+
.hasFieldOrPropertyWithValue("requireHostnameValidation", false);
103135
});
104136
}
105137

0 commit comments

Comments
 (0)