diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
index 51046e33f..3cf10c4f3 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java
@@ -49,6 +49,7 @@ import com.mongodb.Mongo;
*
* @author Mark Pollack
* @author Oliver Gierke
+ * @author Thomas Darimont
*/
@Configuration
public abstract class AbstractMongoConfiguration {
@@ -60,6 +61,16 @@ public abstract class AbstractMongoConfiguration {
*/
protected abstract String getDatabaseName();
+ /**
+ * Return the name of the authentication database to use. Defaults to {@literal null} and will turn into the value
+ * returned by {@link #getDatabaseName()} later on effectively.
+ *
+ * @return
+ */
+ protected String getAuthenticationDatabaseName() {
+ return null;
+ }
+
/**
* Return the {@link Mongo} instance to connect to. Annotate with {@link Bean} in case you want to expose a
* {@link Mongo} instance to the {@link org.springframework.context.ApplicationContext}.
@@ -91,14 +102,7 @@ public abstract class AbstractMongoConfiguration {
*/
@Bean
public SimpleMongoDbFactory mongoDbFactory() throws Exception {
-
- UserCredentials credentials = getUserCredentials();
-
- if (credentials == null) {
- return new SimpleMongoDbFactory(mongo(), getDatabaseName());
- } else {
- return new SimpleMongoDbFactory(mongo(), getDatabaseName(), credentials);
- }
+ return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials(), getAuthenticationDatabaseName());
}
/**
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
index 6e65a7c63..be6c1ff9e 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoDbFactoryParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2012 by the original author(s).
+ * Copyright 2011-2013 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ import com.mongodb.MongoURI;
*
* @author Jon Brisbin
* @author Oliver Gierke
+ * @author Thomas Darimont
*/
public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
@@ -70,6 +71,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
String uri = element.getAttribute("uri");
String mongoRef = element.getAttribute("mongo-ref");
String dbname = element.getAttribute("dbname");
+
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
// Common setup
@@ -92,12 +94,9 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
dbFactoryBuilder.addConstructorArgValue(registerMongoBeanDefinition(element, parserContext));
}
- dbname = StringUtils.hasText(dbname) ? dbname : "db";
- dbFactoryBuilder.addConstructorArgValue(dbname);
-
- if (userCredentials != null) {
- dbFactoryBuilder.addConstructorArgValue(userCredentials);
- }
+ dbFactoryBuilder.addConstructorArgValue(StringUtils.hasText(dbname) ? dbname : "db");
+ dbFactoryBuilder.addConstructorArgValue(userCredentials);
+ dbFactoryBuilder.addConstructorArgValue(element.getAttribute("authentication-dbname"));
BeanDefinitionBuilder writeConcernPropertyEditorBuilder = getWriteConcernPropertyEditorBuilder();
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoAdmin.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoAdmin.java
index 2406c7590..804ad5e59 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoAdmin.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoAdmin.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2012 the original author or authors.
+ * Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import com.mongodb.Mongo;
* Mongo server administration exposed via JMX annotations
*
* @author Mark Pollack
+ * @author Thomas Darimont
*/
@ManagedResource(description = "Mongo Admin Operations")
public class MongoAdmin implements MongoAdminOperations {
@@ -34,6 +35,7 @@ public class MongoAdmin implements MongoAdminOperations {
private final Mongo mongo;
private String username;
private String password;
+ private String authenticationDatabaseName;
public MongoAdmin(Mongo mongo) {
Assert.notNull(mongo);
@@ -82,7 +84,16 @@ public class MongoAdmin implements MongoAdminOperations {
this.password = password;
}
+ /**
+ * Sets the authenticationDatabaseName to use to authenticate with the Mongo database.
+ *
+ * @param authenticationDatabaseName The authenticationDatabaseName to use.
+ */
+ public void setAuthenticationDatabaseName(String authenticationDatabaseName) {
+ this.authenticationDatabaseName = authenticationDatabaseName;
+ }
+
DB getDB(String databaseName) {
- return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password));
+ return MongoDbUtils.getDB(mongo, databaseName, new UserCredentials(username, password), authenticationDatabaseName);
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
index aaa653c48..11a46bda6 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoDbUtils.java
@@ -33,6 +33,7 @@ import com.mongodb.Mongo;
* @author Graeme Rocher
* @author Oliver Gierke
* @author Randy Watler
+ * @author Thomas Darimont
* @since 1.0
*/
public abstract class MongoDbUtils {
@@ -54,7 +55,7 @@ public abstract class MongoDbUtils {
* @return the {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName) {
- return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true);
+ return doGetDB(mongo, databaseName, UserCredentials.NO_CREDENTIALS, true, databaseName);
}
/**
@@ -66,15 +67,22 @@ public abstract class MongoDbUtils {
* @return the {@link DB} connection
*/
public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials) {
+ return getDB(mongo, databaseName, credentials, databaseName);
+ }
+
+ public static DB getDB(Mongo mongo, String databaseName, UserCredentials credentials,
+ String authenticationDatabaseName) {
Assert.notNull(mongo, "No Mongo instance specified!");
Assert.hasText(databaseName, "Database name must be given!");
Assert.notNull(credentials, "Credentials must not be null, use UserCredentials.NO_CREDENTIALS!");
+ Assert.hasText(authenticationDatabaseName, "Authentication database name must not be null or empty!");
- return doGetDB(mongo, databaseName, credentials, true);
+ return doGetDB(mongo, databaseName, credentials, true, authenticationDatabaseName);
}
- private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate) {
+ private static DB doGetDB(Mongo mongo, String databaseName, UserCredentials credentials, boolean allowCreate,
+ String authenticationDatabaseName) {
DbHolder dbHolder = (DbHolder) TransactionSynchronizationManager.getResource(mongo);
@@ -103,14 +111,16 @@ public abstract class MongoDbUtils {
DB db = mongo.getDB(databaseName);
boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword();
- synchronized (db) {
+ DB authDb = databaseName.equals(authenticationDatabaseName) ? db : mongo.getDB(authenticationDatabaseName);
- if (credentialsGiven && !db.isAuthenticated()) {
+ synchronized (authDb) {
+
+ if (credentialsGiven && !authDb.isAuthenticated()) {
String username = credentials.getUsername();
String password = credentials.hasPassword() ? credentials.getPassword() : null;
- if (!db.authenticate(username, password == null ? null : password.toCharArray())) {
+ if (!authDb.authenticate(username, password == null ? null : password.toCharArray())) {
throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], "
+ credentials.toString(), databaseName, credentials);
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
index 116676b5f..0a9d8e4b7 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/SimpleMongoDbFactory.java
@@ -23,6 +23,7 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
import com.mongodb.DB;
import com.mongodb.Mongo;
@@ -44,6 +45,8 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
private final boolean mongoInstanceCreated;
private final UserCredentials credentials;
private final PersistenceExceptionTranslator exceptionTranslator;
+ private final String authenticationDatabaseName;
+
private WriteConcern writeConcern;
/**
@@ -53,7 +56,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* @param databaseName database name, not be {@literal null} or empty.
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName) {
- this(mongo, databaseName, UserCredentials.NO_CREDENTIALS, false);
+ this(mongo, databaseName, null);
}
/**
@@ -64,7 +67,20 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
* @param credentials username and password.
*/
public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials) {
- this(mongo, databaseName, credentials, false);
+ this(mongo, databaseName, credentials, false, null);
+ }
+
+ /**
+ * Create an instance of SimpleMongoDbFactory given the Mongo instance, database name, and username/password
+ *
+ * @param mongo Mongo instance, must not be {@literal null}.
+ * @param databaseName Database name, must not be {@literal null} or empty.
+ * @param credentials username and password.
+ * @param authenticationDatabaseName the database name to use for authentication
+ */
+ public SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
+ String authenticationDatabaseName) {
+ this(mongo, databaseName, credentials, false, authenticationDatabaseName);
}
/**
@@ -77,11 +93,12 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
*/
@SuppressWarnings("deprecation")
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
- this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())), true);
+ this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), parseChars(uri.getPassword())),
+ true, uri.getDatabase());
}
private SimpleMongoDbFactory(Mongo mongo, String databaseName, UserCredentials credentials,
- boolean mongoInstanceCreated) {
+ boolean mongoInstanceCreated, String authenticationDatabaseName) {
Assert.notNull(mongo, "Mongo must not be null");
Assert.hasText(databaseName, "Database name must not be empty");
@@ -93,6 +110,11 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
this.mongoInstanceCreated = mongoInstanceCreated;
this.credentials = credentials == null ? UserCredentials.NO_CREDENTIALS : credentials;
this.exceptionTranslator = new MongoExceptionTranslator();
+ this.authenticationDatabaseName = StringUtils.hasText(authenticationDatabaseName) ? authenticationDatabaseName
+ : databaseName;
+
+ Assert.isTrue(this.authenticationDatabaseName.matches("[\\w-]+"),
+ "Authentication database name must only contain letters, numbers, underscores and dashes!");
}
/**
@@ -120,7 +142,7 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
Assert.hasText(dbName, "Database name must not be empty.");
- DB db = MongoDbUtils.getDB(mongo, dbName, credentials);
+ DB db = MongoDbUtils.getDB(mongo, dbName, credentials, authenticationDatabaseName);
if (writeConcern != null) {
db.setWriteConcern(writeConcern);
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/monitor/ServerInfo.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/monitor/ServerInfo.java
index 3381463d7..de2bb64dd 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/monitor/ServerInfo.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/monitor/ServerInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.4.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.4.xsd
index 27d9c86ad..12a864d3c 100644
--- a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.4.xsd
+++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.4.xsd
@@ -56,6 +56,13 @@ The name of the database to connect to. Default is 'db'.
]]>
+
+
+
+
+
() {
- public Void doInDB(DB db) throws MongoException, DataAccessException {
- db.addUser("admin", "admin".toCharArray());
- return null;
- }
- });
-
factory = new ThreadPoolExecutorFactoryBean();
factory.setCorePoolSize(2);
factory.setMaxPoolSize(10);
@@ -96,6 +90,14 @@ public class MongoDbUtilsIntegrationTests {
@Test
public void authenticatesCorrectlyInMultithreadedEnvironment() throws Exception {
+ // Create sample user
+ template.execute(new DbCallback() {
+ public Void doInDB(DB db) throws MongoException, DataAccessException {
+ db.addUser("admin", "admin".toCharArray());
+ return null;
+ }
+ });
+
Callable callable = new Callable() {
public Void call() throws Exception {
@@ -122,4 +124,45 @@ public class MongoDbUtilsIntegrationTests {
fail("Exception occurred!" + exception);
}
}
+
+ /**
+ * @see DATAMONGO-789
+ */
+ @Test
+ public void authenticatesCorrectlyWithAuthenticationDB() throws Exception {
+
+ // Create sample user
+ template.execute(new DbCallback() {
+ public Void doInDB(DB db) throws MongoException, DataAccessException {
+ db.getSisterDB("admin").addUser("admin", "admin".toCharArray());
+ return null;
+ }
+ });
+
+ Callable callable = new Callable() {
+ public Void call() throws Exception {
+
+ try {
+ DB db = MongoDbUtils.getDB(mongo, DATABASE_NAME, CREDENTIALS, AUTHENTICATION_DATABASE_NAME);
+ assertThat(db, is(notNullValue()));
+ } catch (Exception o_O) {
+ MongoDbUtilsIntegrationTests.this.exception = o_O;
+ }
+
+ return null;
+ }
+ };
+
+ List> callables = new ArrayList>();
+
+ for (int i = 0; i < 10; i++) {
+ callables.add(callable);
+ }
+
+ service.invokeAll(callables);
+
+ if (exception != null) {
+ fail("Exception occurred!" + exception);
+ }
+ }
}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SimpleMongoDbFactoryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SimpleMongoDbFactoryUnitTests.java
index b2c0c844d..89e176975 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SimpleMongoDbFactoryUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/SimpleMongoDbFactoryUnitTests.java
@@ -77,6 +77,16 @@ public class SimpleMongoDbFactoryUnitTests {
assertThat(ReflectionTestUtils.getField(mongoDbFactory, "databaseName").toString(), is("myDatabase"));
}
+ /**
+ * @see DATAMONGO-789
+ */
+ @Test
+ public void defaultsAuthenticationDatabaseToDatabase() {
+
+ SimpleMongoDbFactory factory = new SimpleMongoDbFactory(mongo, "foo");
+ assertThat(ReflectionTestUtils.getField(factory, "authenticationDatabaseName"), is((Object) "foo"));
+ }
+
private void rejectsDatabaseName(String databaseName) {
try {
diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml
index 4718bdc05..056c63812 100644
--- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml
+++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/MongoNamespaceTests-context.xml
@@ -37,6 +37,14 @@
dbname="database"
username="joe"
password="secret"/>
+
+