summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/user_management_helpers.js21
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.cpp22
-rw-r--r--src/mongo/shell/db.js25
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;