diff options
-rw-r--r-- | jstests/user_management_helpers.js | 21 | ||||
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.cpp | 22 | ||||
-rw-r--r-- | src/mongo/shell/db.js | 25 |
3 files changed, 64 insertions, 4 deletions
diff --git a/jstests/user_management_helpers.js b/jstests/user_management_helpers.js index 1b718a198b3..551edfa2412 100644 --- a/jstests/user_management_helpers.js +++ b/jstests/user_management_helpers.js @@ -70,4 +70,25 @@ function assertHasRole(rolesArray, roleName, roleDB) { // Test dropAllUsers db.dropAllUsers() assert.eq(0, db.getUsers().length); + + // Test password digestion + assert.throws(function() { + db.addUser({user:'user1', pwd:'x', roles:[], digestPassword: true});}); + assert.throws(function() { + db.addUser({user:'user1', pwd:'x', roles:[], digestPassword: false});}); + assert.throws(function() { + db.addUser({user:'user1', pwd:'x', roles:[], passwordDigestor: 'foo'});}); + db.addUser({user:'user1', pwd:'x', roles:[], passwordDigestor:"server"}); + db.addUser({user:'user2', pwd:'x', roles:[], passwordDigestor:"client"}); + assert(db.auth('user1', 'x')); + assert(db.auth('user2', 'x')); + + assert.throws(function() { db.updateUser('user1', {pwd:'y', digestPassword: true});}); + assert.throws(function() { db.updateUser('user1', {pwd:'y', digestPassword: false});}); + assert.throws(function() { db.updateUser('user1', {pwd:'y', passwordDigestor: 'foo'});}); + db.updateUser('user1', {pwd:'y', passwordDigestor: 'server'}); + db.updateUser('user2', {pwd:'y', passwordDigestor: 'client'}); + assert(db.auth('user1', 'y')); + assert(db.auth('user2', 'y')); + }(db));
\ No newline at end of file diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp index e03ff1c4478..cc2615ad13b 100644 --- a/src/mongo/db/auth/user_management_commands_parser.cpp +++ b/src/mongo/db/auth/user_management_commands_parser.cpp @@ -212,6 +212,7 @@ namespace auth { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("customData"); + validFieldNames.insert("digestPassword"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); @@ -239,16 +240,29 @@ namespace auth { // Parse password if (cmdObj.hasField("pwd")) { - std::string clearTextPassword; - status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); + std::string password; + status = bsonExtractStringField(cmdObj, "pwd", &password); if (!status.isOK()) { return status; } - if (clearTextPassword.empty()) { + if (password.empty()) { return Status(ErrorCodes::BadValue, "User passwords must not be empty"); } - parsedArgs->hashedPassword = auth::createPasswordDigest(userName, clearTextPassword); + bool digestPassword; // True if the server should digest the password + status = bsonExtractBooleanFieldWithDefault(cmdObj, + "digestPassword", + true, + &digestPassword); + if (!status.isOK()) { + return status; + } + + if (digestPassword) { + parsedArgs->hashedPassword = auth::createPasswordDigest(userName, password); + } else { + parsedArgs->hashedPassword = password; + } parsedArgs->hasHashedPassword = true; } diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index d24181cd2d1..bf921b4c052 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -943,6 +943,27 @@ DB.prototype._createUser = function(userObj, replicatedTo, timeout) { } } +DB.prototype._modifyCommandToDigestPasswordIfNecessary = function(cmdObj, username) { + if (!cmdObj["pwd"]) { + return; + } + if (cmdObj.hasOwnProperty("digestPassword")) { + throw Error("Cannot specify 'digestPassword' through the user management shell helpers, " + + "use 'passwordDigestor' instead"); + } + var passwordDigestor = cmdObj["passwordDigestor"] ? cmdObj["passwordDigestor"] : "client"; + if (passwordDigestor == "server") { + cmdObj["digestPassword"] = true; + } else if (passwordDigestor == "client") { + cmdObj["pwd"] = _hashPassword(username, cmdObj["pwd"]); + cmdObj["digestPassword"] = false; + } else { + throw Error("'passwordDigestor' must be either 'server' or 'client', got: '" + + passwordDigestor + "'"); + } + delete cmdObj["passwordDigestor"]; +} + // Returns true if it worked, false if the createUser command wasn't found, and throws on all other // failures DB.prototype._createUserWithCommand = function(userObj, replicatedTo, timeout) { @@ -951,6 +972,8 @@ DB.prototype._createUserWithCommand = function(userObj, replicatedTo, timeout) { cmdObj = Object.extend(cmdObj, userObj); delete cmdObj["user"]; + this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); + replicatedTo = replicatedTo != null ? replicatedTo : "majority"; timeout = timeout || 30 * 1000; cmdObj["writeConcern"] = { w: replicatedTo, wtimeout: timeout }; @@ -1059,6 +1082,8 @@ DB.prototype.updateUser = function(name, updateObject, writeConcern) { var cmdObj = {updateUser:name}; cmdObj = Object.extend(cmdObj, updateObject); cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern; + this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name); + var res = this.runCommand(cmdObj); if (res.ok) { return; |