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 dd798ff19..b8fd5d34c 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 @@ -104,12 +104,13 @@ public abstract class MongoDbUtils { DB db = mongo.getDB(databaseName); boolean credentialsGiven = credentials.hasUsername() && credentials.hasPassword(); - if (credentialsGiven && !db.isAuthenticated()) { + synchronized (db) { - String username = credentials.getUsername(); - String password = credentials.hasPassword() ? credentials.getPassword() : null; + if (credentialsGiven && !db.isAuthenticated()) { + + String username = credentials.getUsername(); + String password = credentials.hasPassword() ? credentials.getPassword() : null; - synchronized (db) { if (!db.authenticate(username, password == null ? null : password.toCharArray())) { throw new CannotGetMongoDbConnectionException("Failed to authenticate to database [" + databaseName + "], username = [" + username + "], password = [" + password + "]", databaseName, credentials); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsIntegrationTests.java new file mode 100644 index 000000000..47b78c639 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoDbUtilsIntegrationTests.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.core; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.dao.DataAccessException; +import org.springframework.data.authentication.UserCredentials; +import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean; + +import com.mongodb.DB; +import com.mongodb.Mongo; +import com.mongodb.MongoException; + +/** + * Integration tests for {@link MongoDbUtils}. + * + * @author Oliver Gierke + */ +public class MongoDbUtilsIntegrationTests { + + static final String DATABASE_NAME = "dbAuthTests"; + static final UserCredentials CREDENTIALS = new UserCredentials("admin", "admin"); + + static Mongo mongo; + static MongoTemplate template; + static ThreadPoolExecutorFactoryBean factory; + static ExecutorService service; + + Exception exception; + + @BeforeClass + public static void setUp() throws Exception { + + mongo = new Mongo(); + template = new MongoTemplate(mongo, DATABASE_NAME); + + // Create sample user + template.execute(new DbCallback() { + public Void doInDB(DB db) throws MongoException, DataAccessException { + db.addUser("admin", "admin".toCharArray()); + return null; + } + }); + + factory = new ThreadPoolExecutorFactoryBean(); + factory.setCorePoolSize(2); + factory.setMaxPoolSize(10); + factory.setWaitForTasksToCompleteOnShutdown(true); + factory.afterPropertiesSet(); + + service = factory.getObject(); + } + + @AfterClass + public static void tearDown() { + + factory.destroy(); + + // Remove test database + + template.execute(new DbCallback() { + public Void doInDB(DB db) throws MongoException, DataAccessException { + db.dropDatabase(); + return null; + } + }); + } + + /** + * @see DATAMONGO-585 + */ + @Test + public void authenticatesCorrectlyInMultithreadedEnvironment() throws Exception { + + Callable callable = new Callable() { + public Void call() throws Exception { + + try { + DB db = MongoDbUtils.getDB(mongo, DATABASE_NAME, CREDENTIALS); + 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); + } + } +}