diff --git a/MongoDB.Driver/Communication/FeatureDetection/FeatureSetDetector.cs b/MongoDB.Driver/Communication/FeatureDetection/FeatureSetDetector.cs
index 9de04a399df..2f812f8dc40 100644
--- a/MongoDB.Driver/Communication/FeatureDetection/FeatureSetDetector.cs
+++ b/MongoDB.Driver/Communication/FeatureDetection/FeatureSetDetector.cs
@@ -32,7 +32,8 @@ internal class FeatureSetDetector
new ServerParameterDependency("enableExperimentalWriteCommands")), // and for now must be explicitly enabled in the server
// added in 2.5.3
- new FeatureDetector(FeatureId.MaxTime, new ServerVersionDependency(2, 5, 3)) // while MaxTime was added in 2.5.2 the FailPoint for it wasn't added until 2.5.3
+ new FeatureDetector(FeatureId.MaxTime, new ServerVersionDependency(2, 5, 3)), // while MaxTime was added in 2.5.2 the FailPoint for it wasn't added until 2.5.3
+ new FeatureDetector(FeatureId.UserManagementCommands, new ServerVersionDependency(2, 5, 3))
};
// public methods
diff --git a/MongoDB.Driver/FeatureId.cs b/MongoDB.Driver/FeatureId.cs
index ea2c6cae8ec..351ab6bc3f7 100644
--- a/MongoDB.Driver/FeatureId.cs
+++ b/MongoDB.Driver/FeatureId.cs
@@ -39,6 +39,10 @@ public enum FeatureId
///
/// The max time feature.
///
- MaxTime
+ MaxTime,
+ ///
+ /// The user management commands.
+ ///
+ UserManagementCommands
}
-}
+}
\ No newline at end of file
diff --git a/MongoDB.Driver/MongoDatabase.cs b/MongoDB.Driver/MongoDatabase.cs
index 507cf483227..e72d8a29ba4 100644
--- a/MongoDB.Driver/MongoDatabase.cs
+++ b/MongoDB.Driver/MongoDatabase.cs
@@ -259,17 +259,20 @@ public virtual MongoDatabaseSettings Settings
/// Adds a user to this database.
///
/// The user.
+ [Obsolete("Use the new user management command 'createUser' or 'updateUser'.")]
public virtual void AddUser(MongoUser user)
{
- var users = GetCollection("system.users");
- var document = users.FindOne(Query.EQ("user", user.Username));
- if (document == null)
+ using (RequestStart(ReadPreference.Primary))
{
- document = new BsonDocument("user", user.Username);
+ if (_server.RequestConnection.ServerInstance.Supports(FeatureId.UserManagementCommands))
+ {
+ AddUserWithUserManagementCommands(user);
+ }
+ else
+ {
+ AddUserWithInsert(user);
+ }
}
- document["readOnly"] = user.IsReadOnly;
- document["pwd"] = user.PasswordHash;
- users.Save(document);
}
///
@@ -467,19 +470,18 @@ public virtual object FetchDBRefAs(Type documentType, MongoDBRef dbRef)
/// Finds all users of this database.
///
/// An array of users.
+ [Obsolete("Use the new user management command 'usersInfo'.")]
public virtual MongoUser[] FindAllUsers()
{
- var result = new List();
- var users = GetCollection("system.users");
- foreach (var document in users.FindAll())
+ using (RequestStart(ReadPreference.Primary))
{
- var username = document["user"].AsString;
- var passwordHash = document["pwd"].AsString;
- var readOnly = document["readOnly"].ToBoolean();
- var user = new MongoUser(username, passwordHash, readOnly);
- result.Add(user);
- };
- return result.ToArray();
+ if (_server.RequestConnection.ServerInstance.Supports(FeatureId.UserManagementCommands))
+ {
+ return FindAllUsersWithUserManagementCommands();
+ }
+
+ return FindAllUsersWithQuery();
+ }
}
///
@@ -487,20 +489,17 @@ public virtual MongoUser[] FindAllUsers()
///
/// The username.
/// The user.
+ [Obsolete("Use the new user management command 'usersInfo'.")]
public virtual MongoUser FindUser(string username)
{
- var users = GetCollection("system.users");
- var query = Query.EQ("user", username);
- var document = users.FindOne(query);
- if (document != null)
- {
- var passwordHash = document["pwd"].AsString;
- var readOnly = document["readOnly"].ToBoolean();
- return new MongoUser(username, passwordHash, readOnly);
- }
- else
+ using (RequestStart(ReadPreference.Primary))
{
- return null;
+ if (_server.RequestConnection.ServerInstance.Supports(FeatureId.UserManagementCommands))
+ {
+ return FindUserWithUserManagementCommands(username);
+ }
+
+ return FindUserWithQuery(username);
}
}
@@ -796,6 +795,7 @@ public virtual bool IsCollectionNameValid(string collectionName, out string mess
/// Removes a user from this database.
///
/// The user to remove.
+ [Obsolete("Use RunCommand with a { dropUser: } document.")]
public virtual void RemoveUser(MongoUser user)
{
RemoveUser(user.Username);
@@ -805,10 +805,21 @@ public virtual void RemoveUser(MongoUser user)
/// Removes a user from this database.
///
/// The username to remove.
+ [Obsolete("Use RunCommand with a { dropUser: } document.")]
public virtual void RemoveUser(string username)
{
- var users = GetCollection("system.users");
- users.Remove(Query.EQ("user", username));
+ using (RequestStart(ReadPreference.Primary))
+ {
+ if (_server.RequestConnection.ServerInstance.Supports(FeatureId.UserManagementCommands))
+ {
+ RunCommand(new CommandDocument("dropUser", username));
+ }
+ else
+ {
+ var users = GetCollection("system.users");
+ users.Remove(Query.EQ("user", username));
+ }
+ }
}
///
@@ -1009,6 +1020,118 @@ public override string ToString()
}
// private methods
+ #pragma warning disable 618
+ private void AddUserWithInsert(MongoUser user)
+ {
+ var users = GetCollection("system.users");
+ var document = users.FindOne(Query.EQ("user", user.Username));
+ if (document == null)
+ {
+ document = new BsonDocument("user", user.Username);
+ }
+ document["readOnly"] = user.IsReadOnly;
+ document["pwd"] = user.PasswordHash;
+ users.Save(document);
+ }
+ #pragma warning restore
+
+ #pragma warning disable 618
+ private void AddUserWithUserManagementCommands(MongoUser user)
+ {
+ var usersInfo = RunCommand(new CommandDocument("usersInfo", user.Username));
+
+ var roles = new BsonArray();
+ if (_name == "admin")
+ {
+ roles.Add(user.IsReadOnly ? "readAnyDatabase" : "root");
+ }
+ else
+ {
+ roles.Add(user.IsReadOnly ? "read" : "dbOwner");
+ }
+
+ var commandName = "createUser";
+
+ if (usersInfo.Response.Contains("users") && usersInfo.Response["users"].AsBsonArray.Count > 0)
+ {
+ commandName = "updateUser";
+ }
+
+ var userCommand = new CommandDocument
+ {
+ { commandName, user.Username },
+ { "pwd", user.PasswordHash },
+ { "digestPassword", false },
+ { "roles", roles }
+ };
+
+ RunCommand(userCommand);
+ }
+ #pragma warning restore
+
+ #pragma warning disable 618
+ private MongoUser FindUserWithQuery(string username)
+ {
+ var users = GetCollection("system.users");
+ var query = Query.EQ("user", username);
+ var document = users.FindOne(query);
+ if (document != null)
+ {
+ var passwordHash = document.GetValue("pwd", "").AsString;
+ var readOnly = document["readOnly"].ToBoolean();
+ return new MongoUser(username, passwordHash, readOnly);
+ }
+
+ return null;
+ }
+ #pragma warning restore
+
+ #pragma warning disable 618
+ private MongoUser FindUserWithUserManagementCommands(string username)
+ {
+ var usersInfoResult = RunCommand(new CommandDocument("usersInfo", username));
+ if (usersInfoResult.Response.Contains("users") && usersInfoResult.Response["users"].AsBsonArray.Count > 0)
+ {
+ return new MongoUser(username, new PasswordEvidence(""), false);
+ }
+
+ return null;
+ }
+ #pragma warning restore
+
+ #pragma warning disable 618
+ private MongoUser[] FindAllUsersWithQuery()
+ {
+ var results = new List();
+ var users = GetCollection("system.users");
+ foreach (var document in users.FindAll())
+ {
+ var username = document["user"].AsString;
+ var passwordHash = document.GetValue("pwd", "").AsString;
+ var readOnly = document["readOnly"].ToBoolean();
+ var user = new MongoUser(username, passwordHash, readOnly);
+ results.Add(user);
+ };
+ return results.ToArray();
+ }
+ #pragma warning restore
+
+ #pragma warning disable 618
+ private MongoUser[] FindAllUsersWithUserManagementCommands()
+ {
+ var results = new List();
+ var usersInfoResult = RunCommand(new CommandDocument("usersInfo", 1));
+ if (usersInfoResult.Response.Contains("users"))
+ {
+ foreach (var document in usersInfoResult.Response["users"].AsBsonArray)
+ {
+ results.Add(new MongoUser(document["user"].AsString, new PasswordEvidence(""), false));
+ }
+ }
+ return results.ToArray();
+ }
+ #pragma warning restore
+
private TCommandResult RunCommandAs(
IMongoCommand command,
IBsonSerializer resultSerializer,
diff --git a/MongoDB.Driver/MongoUser.cs b/MongoDB.Driver/MongoUser.cs
index c6a3cfa4bf4..a8989889522 100644
--- a/MongoDB.Driver/MongoUser.cs
+++ b/MongoDB.Driver/MongoUser.cs
@@ -21,6 +21,7 @@ namespace MongoDB.Driver
/// Represents a MongoDB user.
///
[Serializable]
+ [Obsolete("Use the new user management commands instead.")]
public class MongoUser : IEquatable
{
// private fields
diff --git a/MongoDB.DriverUnitTests/MongoDatabaseTests.cs b/MongoDB.DriverUnitTests/MongoDatabaseTests.cs
index 5d5ebd924c3..37fd920bbdd 100644
--- a/MongoDB.DriverUnitTests/MongoDatabaseTests.cs
+++ b/MongoDB.DriverUnitTests/MongoDatabaseTests.cs
@@ -334,26 +334,49 @@ public void TestSetProfilingLevel()
}
[Test]
- public void TestUserMethods()
+ [TestCase("user1", "pass1", true)]
+ [TestCase("user2", "pass2", false)]
+ public void TestUserMethods(string username, string password, bool isReadOnly)
{
- var collection = _database.GetCollection("system.users");
- collection.RemoveAll();
- _database.AddUser(new MongoUser("username", new PasswordEvidence("password"), true));
- Assert.AreEqual(1, collection.Count());
-
- var user = _database.FindUser("username");
- Assert.AreEqual("username", user.Username);
- Assert.AreEqual(MongoUtils.Hash("username:mongo:password"), user.PasswordHash);
- Assert.AreEqual(true, user.IsReadOnly);
-
- var users = _database.FindAllUsers();
- Assert.AreEqual(1, users.Length);
- Assert.AreEqual("username", users[0].Username);
- Assert.AreEqual(MongoUtils.Hash("username:mongo:password"), users[0].PasswordHash);
- Assert.AreEqual(true, users[0].IsReadOnly);
-
- _database.RemoveUser(user);
- Assert.AreEqual(0, collection.Count());
+ #pragma warning disable 618
+ using (_database.RequestStart(ReadPreference.Primary))
+ {
+ bool usesCommands = _database.Server.RequestConnection.ServerInstance.Supports(FeatureId.UserManagementCommands);
+ if (usesCommands)
+ {
+ _database.RunCommand("dropAllUsersFromDatabase");
+ }
+ else
+ {
+ var collection = _database.GetCollection("system.users");
+ collection.RemoveAll();
+ }
+
+ _database.AddUser(new MongoUser(username, new PasswordEvidence(password), isReadOnly));
+
+ var user = _database.FindUser(username);
+ Assert.IsNotNull(user);
+ Assert.AreEqual(username, user.Username);
+ if (!usesCommands)
+ {
+ Assert.AreEqual(MongoUtils.Hash(string.Format("{0}:mongo:{1}", username, password)), user.PasswordHash);
+ Assert.AreEqual(isReadOnly, user.IsReadOnly);
+ }
+
+ var users = _database.FindAllUsers();
+ Assert.AreEqual(1, users.Length);
+ Assert.AreEqual(username, users[0].Username);
+ if (!usesCommands)
+ {
+ Assert.AreEqual(MongoUtils.Hash(string.Format("{0}:mongo:{1}", username, password)), users[0].PasswordHash);
+ Assert.AreEqual(isReadOnly, users[0].IsReadOnly);
+ }
+
+ _database.RemoveUser(user);
+ user = _database.FindUser(username);
+ Assert.IsNull(user);
+ #pragma warning restore
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/MongoDB.DriverUnitTests/MongoUserTests.cs b/MongoDB.DriverUnitTests/MongoUserTests.cs
index 16c4831626c..40838103a08 100644
--- a/MongoDB.DriverUnitTests/MongoUserTests.cs
+++ b/MongoDB.DriverUnitTests/MongoUserTests.cs
@@ -16,6 +16,7 @@
using MongoDB.Driver;
using NUnit.Framework;
+#pragma warning disable 618
namespace MongoDB.DriverUnitTests
{
[TestFixture]
@@ -87,3 +88,4 @@ public void TestEquals()
}
}
}
+#pragma warning restore
\ No newline at end of file