diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetails.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetails.java index 4d6fb5c3d1f..74a91c9a1c8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetails.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetails.java @@ -16,6 +16,9 @@ package org.springframework.boot.autoconfigure.mongo; +import java.util.ArrayList; +import java.util.List; + import com.mongodb.ConnectionString; /** @@ -24,6 +27,7 @@ import com.mongodb.ConnectionString; * @author Moritz Halbritter * @author Andy Wilkinson * @author Phillip Webb + * @author Scott Frederick * @since 3.1.0 */ public class PropertiesMongoConnectionDetails implements MongoConnectionDetails { @@ -44,7 +48,9 @@ public class PropertiesMongoConnectionDetails implements MongoConnectionDetails if (this.properties.getUsername() != null) { builder.append(this.properties.getUsername()); builder.append(":"); - builder.append(this.properties.getPassword()); + if (this.properties.getPassword() != null) { + builder.append(this.properties.getPassword()); + } builder.append("@"); } builder.append((this.properties.getHost() != null) ? this.properties.getHost() : "localhost"); @@ -55,20 +61,12 @@ public class PropertiesMongoConnectionDetails implements MongoConnectionDetails if (this.properties.getAdditionalHosts() != null) { builder.append(String.join(",", this.properties.getAdditionalHosts())); } - if (this.properties.getMongoClientDatabase() != null || this.properties.getReplicaSetName() != null - || this.properties.getAuthenticationDatabase() != null) { - builder.append("/"); - if (this.properties.getMongoClientDatabase() != null) { - builder.append(this.properties.getMongoClientDatabase()); - } - else if (this.properties.getAuthenticationDatabase() != null) { - builder.append(this.properties.getAuthenticationDatabase()); - } - if (this.properties.getReplicaSetName() != null) { - builder.append("?"); - builder.append("replicaSet="); - builder.append(this.properties.getReplicaSetName()); - } + builder.append("/"); + builder.append(this.properties.getMongoClientDatabase()); + List options = getOptions(); + if (!options.isEmpty()) { + builder.append("?"); + builder.append(String.join("&", options)); } return new ConnectionString(builder.toString()); } @@ -79,4 +77,15 @@ public class PropertiesMongoConnectionDetails implements MongoConnectionDetails PropertiesMongoConnectionDetails.this.properties.getGridfs().getBucket()); } + private List getOptions() { + List options = new ArrayList<>(); + if (this.properties.getReplicaSetName() != null) { + options.add("replicaSet=" + this.properties.getReplicaSetName()); + } + if (this.properties.getUsername() != null && this.properties.getAuthenticationDatabase() != null) { + options.add("authSource=" + this.properties.getAuthenticationDatabase()); + } + return options; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index 31947cb6824..342461ffc40 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; +import com.mongodb.MongoCredential; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import com.mongodb.client.internal.MongoClientImpl; @@ -107,6 +108,95 @@ class MongoAutoConfigurationTests { }); } + @Test + void doesNotConfigureCredentialsWithoutUsername() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.password=secret", + "spring.data.mongodb.authentication-database=authdb") + .run((context) -> assertThat(getSettings(context).getCredential()).isNull()); + } + + @Test + void configuresCredentialsFromPropertiesWithDefaultDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("test"); + }); + } + + @Test + void configuresCredentialsFromPropertiesWithDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret", + "spring.data.mongodb.database=mydb") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("mydb"); + }); + } + + @Test + void configuresCredentialsFromPropertiesWithAuthDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret", + "spring.data.mongodb.database=mydb", "spring.data.mongodb.authentication-database=authdb") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("authdb"); + }); + } + + @Test + void doesNotConfigureCredentialsWithoutUsernameInUri() { + this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://localhost/mydb?authSource=authdb") + .run((context) -> assertThat(getSettings(context).getCredential()).isNull()); + } + + @Test + void configuresCredentialsFromUriPropertyWithDefaultDatabase() { + this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("admin"); + }); + } + + @Test + void configuresCredentialsFromUriPropertyWithDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb", + "spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("mydb"); + }); + } + + @Test + void configuresCredentialsFromUriPropertyWithAuthDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb", + "spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("authdb"); + }); + } + @Test void configuresSingleClient() { this.contextRunner.withUserConfiguration(FallbackMongoClientConfig.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java index 44e311be1d7..7f3fe1ef0b1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java @@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; +import com.mongodb.MongoCredential; import com.mongodb.ReadPreference; import com.mongodb.connection.AsynchronousSocketChannelStreamFactoryFactory; import com.mongodb.connection.SslSettings; @@ -121,6 +122,95 @@ class MongoReactiveAutoConfigurationTests { }); } + @Test + void doesNotConfigureCredentialsWithoutUsername() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.password=secret", + "spring.data.mongodb.authentication-database=authdb") + .run((context) -> assertThat(getSettings(context).getCredential()).isNull()); + } + + @Test + void configuresCredentialsFromPropertiesWithDefaultDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("test"); + }); + } + + @Test + void configuresCredentialsFromPropertiesWithDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret", + "spring.data.mongodb.database=mydb") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("mydb"); + }); + } + + @Test + void configuresCredentialsFromPropertiesWithAuthDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.username=user", "spring.data.mongodb.password=secret", + "spring.data.mongodb.database=mydb", "spring.data.mongodb.authentication-database=authdb") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("authdb"); + }); + } + + @Test + void doesNotConfigureCredentialsWithoutUsernameInUri() { + this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://localhost/mydb?authSource=authdb") + .run((context) -> assertThat(getSettings(context).getCredential()).isNull()); + } + + @Test + void configuresCredentialsFromUriPropertyWithDefaultDatabase() { + this.contextRunner.withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("admin"); + }); + } + + @Test + void configuresCredentialsFromUriPropertyWithDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb", + "spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("mydb"); + }); + } + + @Test + void configuresCredentialsFromUriPropertyWithAuthDatabase() { + this.contextRunner + .withPropertyValues("spring.data.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb", + "spring.data.mongodb.database=notused", "spring.data.mongodb.authentication-database=notused") + .run((context) -> { + MongoCredential credential = getSettings(context).getCredential(); + assertThat(credential.getUserName()).isEqualTo("user"); + assertThat(credential.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(credential.getSource()).isEqualTo("authdb"); + }); + } + @Test void nettyStreamFactoryFactoryIsConfiguredAutomatically() { AtomicReference eventLoopGroupReference = new AtomicReference<>(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetailsTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetailsTests.java index 2f9887f468d..1a1372f4576 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetailsTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/PropertiesMongoConnectionDetailsTests.java @@ -25,11 +25,66 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link PropertiesMongoConnectionDetails}. * * @author Christoph Dreis + * @author Scott Frederick */ class PropertiesMongoConnectionDetailsTests { private final MongoProperties properties = new MongoProperties(); + @Test + void credentialsCanBeConfiguredWithUsername() { + this.properties.setUsername("user"); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getUsername()).isEqualTo("user"); + assertThat(connectionString.getPassword()).isEmpty(); + assertThat(connectionString.getCredential().getUserName()).isEqualTo("user"); + assertThat(connectionString.getCredential().getPassword()).isEmpty(); + assertThat(connectionString.getCredential().getSource()).isEqualTo("test"); + } + + @Test + void credentialsCanBeConfiguredWithUsernameAndPassword() { + this.properties.setUsername("user"); + this.properties.setPassword("secret".toCharArray()); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getUsername()).isEqualTo("user"); + assertThat(connectionString.getPassword()).isEqualTo("secret".toCharArray()); + assertThat(connectionString.getCredential().getUserName()).isEqualTo("user"); + assertThat(connectionString.getCredential().getPassword()).isEqualTo("secret".toCharArray()); + assertThat(connectionString.getCredential().getSource()).isEqualTo("test"); + } + + @Test + void databaseCanBeConfigured() { + this.properties.setDatabase("db"); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getDatabase()).isEqualTo("db"); + } + + @Test + void databaseHasDefaultWhenNotConfigured() { + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getDatabase()).isEqualTo("test"); + } + + @Test + void authenticationDatabaseCanBeConfigured() { + this.properties.setUsername("user"); + this.properties.setDatabase("db"); + this.properties.setAuthenticationDatabase("authdb"); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getDatabase()).isEqualTo("db"); + assertThat(connectionString.getCredential().getSource()).isEqualTo("authdb"); + assertThat(connectionString.getCredential().getUserName()).isEqualTo("user"); + } + + @Test + void authenticationDatabaseIsNotConfiguredWhenUsernameIsNotConfigured() { + this.properties.setAuthenticationDatabase("authdb"); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getCredential()).isNull(); + } + @Test void replicaSetCanBeConfigured() { this.properties.setReplicaSetName("test"); @@ -37,6 +92,16 @@ class PropertiesMongoConnectionDetailsTests { assertThat(connectionString.getRequiredReplicaSetName()).isEqualTo("test"); } + @Test + void replicaSetCanBeConfiguredWithDatabase() { + this.properties.setUsername("user"); + this.properties.setDatabase("db"); + this.properties.setReplicaSetName("test"); + ConnectionString connectionString = getConnectionString(); + assertThat(connectionString.getDatabase()).isEqualTo("db"); + assertThat(connectionString.getRequiredReplicaSetName()).isEqualTo("test"); + } + private PropertiesMongoConnectionDetails createConnectionDetails() { return new PropertiesMongoConnectionDetails(this.properties); }