mongo/jstests/auth/user_management_commands_me...

227 lines
8.2 KiB
JavaScript

// Ensure that created/updated users have the correct credentials.
// @tags: [requires_persistence]
let mongod = MongoRunner.runMongod({
auth: "",
setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256,PLAIN",
});
const admin = mongod.getDB("admin");
const test = mongod.getDB("test");
function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) {
function checkCredentialRecord(creds, hashLen, saltLen, itCount) {
assert.eq(creds.iterationCount, itCount);
assert.eq(creds.salt.length, saltLen);
assert.eq(creds.storedKey.length, hashLen);
assert.eq(creds.serverKey.length, hashLen);
}
function checkLogin(mech, digestOK, nodigestOK) {
assert(test.auth({user: userid, pwd: passwd, mechanism: mech}));
test.logout();
assert.eq(digestOK, test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: true}));
if (digestOK) {
test.logout();
}
assert.eq(nodigestOK, test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: false}));
if (nodigestOK) {
test.logout();
}
}
assert(admin.auth("admin", "pass"));
const user = admin.system.users.findOne({_id: "test." + userid});
assert.eq(user.credentials.hasOwnProperty("SCRAM-SHA-1"), haveSCRAMSHA1);
assert.eq(user.credentials.hasOwnProperty("SCRAM-SHA-256"), haveSCRAMSHA256);
// usersInfo contains correct mechanisms for the user
const userInfo = assert.commandWorked(test.runCommand({usersInfo: userid}));
assert(Array.isArray(userInfo.users[0].mechanisms));
assert.eq(userInfo.users[0].mechanisms.includes("SCRAM-SHA-1"), haveSCRAMSHA1);
assert.eq(userInfo.users[0].mechanisms.includes("SCRAM-SHA-256"), haveSCRAMSHA256);
// usersInfo with showCredentials shows correct mechanisms and credentials
const userInfoWithCredentials = assert.commandWorked(test.runCommand({usersInfo: userid, showCredentials: true}));
print(tojson(userInfoWithCredentials));
assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty("SCRAM-SHA-1"), haveSCRAMSHA1);
assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty("SCRAM-SHA-256"), haveSCRAMSHA256);
assert(Array.isArray(userInfoWithCredentials.users[0].mechanisms));
assert.eq(userInfoWithCredentials.users[0].mechanisms.includes("SCRAM-SHA-1"), haveSCRAMSHA1);
assert.eq(userInfoWithCredentials.users[0].mechanisms.includes("SCRAM-SHA-256"), haveSCRAMSHA256);
admin.logout();
if (haveSCRAMSHA1) {
checkCredentialRecord(user.credentials["SCRAM-SHA-1"], 28, 24, 10000);
checkLogin("SCRAM-SHA-1", true, false);
checkLogin("PLAIN", false, true);
}
if (haveSCRAMSHA256) {
checkCredentialRecord(user.credentials["SCRAM-SHA-256"], 44, 40, 15000);
checkLogin("SCRAM-SHA-256", false, true);
checkLogin("PLAIN", false, true);
}
}
admin.createUser({user: "admin", pwd: "pass", roles: jsTest.adminUserRoles});
assert(admin.auth("admin", "pass"));
function createUser(db, user) {
assert(admin.auth("admin", "pass"));
db.createUser(user);
admin.logout();
}
function createUserThrows(db, user) {
assert(admin.auth("admin", "pass"));
assert.throws(() => db.createUser(user));
admin.logout();
}
// Unknown mechanism.
createUserThrows(test, {
user: "shalala",
pwd: "pass",
roles: jsTest.basicUserRoles,
mechanisms: ["SCRAM-SHA-1", "SCRAM-SHA-LA-LA"],
});
// By default, users are created with both SCRAM variants.
createUser(test, {user: "user", pwd: "pass", roles: jsTest.basicUserRoles});
checkUser("user", "pass", true, true);
// Request SHA1 only.
createUser(test, {user: "sha1user", pwd: "pass", roles: jsTest.basicUserRoles, mechanisms: ["SCRAM-SHA-1"]});
checkUser("sha1user", "pass", true, false);
// Request SHA256 only.
createUser(test, {user: "sha256user", pwd: "pass", roles: jsTest.basicUserRoles, mechanisms: ["SCRAM-SHA-256"]});
checkUser("sha256user", "pass", false, true);
// Fail passing an empty mechanisms field.
createUserThrows(test, {user: "userNoMech", pwd: "pass", roles: jsTest.basicUserRoles, mechanisms: []});
// Repeat above, but request client-side digesting.
// Only the SCRAM-SHA-1 exclusive version should succeed.
createUserThrows(test, {user: "user2", pwd: "pass", roles: jsTest.basicUserRoles, passwordDisgestor: "client"});
createUser(test, {
user: "sha1user2",
pwd: "pass",
roles: jsTest.basicUserRoles,
mechanisms: ["SCRAM-SHA-1"],
passwordDigestor: "client",
});
checkUser("sha1user2", "pass", true, false);
createUserThrows(test, {
user: "sha256user2",
pwd: "pass",
roles: jsTest.basicUserRoles,
mechanisms: ["SCRAM-SHA-256"],
passwordDigestor: "client",
});
function updateUser(db, user, props) {
assert(admin.auth("admin", "pass"));
db.updateUser(user, props);
admin.logout();
}
function updateUserThrows(db, user, props) {
assert(admin.auth("admin", "pass"));
assert.throws(() => db.updateUser(user, props));
admin.logout();
}
// Update original 1/256 user to just sha-1.
updateUser(test, "user", {pwd: "pass1", mechanisms: ["SCRAM-SHA-1"]});
checkUser("user", "pass1", true, false);
// Then flip to 256-only
updateUser(test, "user", {pwd: "pass256", mechanisms: ["SCRAM-SHA-256"]});
checkUser("user", "pass256", false, true);
// And back to (default) all.
updateUser(test, "user", {pwd: "passAll"});
checkUser("user", "passAll", true, true);
// Trim out mechanisms without changing password.
updateUser(test, "user", {mechanisms: ["SCRAM-SHA-256"]});
checkUser("user", "passAll", false, true);
// Fail when mechanisms is not a subset of the current user.
updateUserThrows(test, "user", {mechanisms: ["SCRAM-SHA-1"]});
// Fail when passing an empty mechanisms field.
updateUserThrows(test, "user", {pwd: "passEmpty", mechanisms: []});
// Succeed if we're using SHA-1 only.
createUser(test, {user: "\u2168", pwd: "pass", roles: jsTest.basicUserRoles, mechanisms: ["SCRAM-SHA-1"]});
checkUser("\u2168", "pass", true, false);
assert(admin.auth("admin", "pass"));
// Demonstrate that usersInfo returns all users with mechanisms lists
const allUsersInfo = assert.commandWorked(test.runCommand({usersInfo: 1}));
allUsersInfo.users.forEach(function (userObj) {
assert(Array.isArray(userObj.mechanisms));
});
// Demonstrate that usersInfo can return all users with credentials
const allUsersInfoWithCredentials = assert.commandWorked(test.runCommand({usersInfo: 1, showCredentials: true}));
allUsersInfoWithCredentials.users.forEach(function (userObj) {
assert(userObj.credentials !== undefined);
assert(!Array.isArray(userObj.credentials));
assert(userObj.mechanisms !== undefined);
assert(Array.isArray(userObj.mechanisms));
});
// Demonstrate that usersInfo can find SCRAM-SHA-1 users
const allSCRAMSHA1UsersInfo = assert.commandWorked(
test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-1"}}),
);
let foundUsers = [];
allSCRAMSHA1UsersInfo.users.forEach(function (userObj) {
foundUsers.push(userObj.user);
});
assert.eq(["sha1user", "sha1user2", "\u2168"], foundUsers);
// Demonstrate that usersInfo can find SCRAM-SHA-256 users
const allSCRAMSHA256UsersInfo = assert.commandWorked(
test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-256"}}),
);
foundUsers = [];
allSCRAMSHA256UsersInfo.users.forEach(function (userObj) {
foundUsers.push(userObj.user);
});
assert.eq(["sha256user", "user"], foundUsers);
MongoRunner.stopMongod(mongod);
// Ensure mechanisms can be enabled and disabled.
function restartWithOneMech(mech) {
const sha1ok = mech === "SCRAM-SHA-1";
const sha256ok = mech === "SCRAM-SHA-256";
mongod = MongoRunner.runMongod({
auth: "",
setParameter: "authenticationMechanisms=" + mech,
restart: mongod,
noCleanData: true,
});
const test = mongod.getDB("test");
assert.eq(test.auth("sha1user", "pass"), sha1ok);
if (sha1ok) {
test.logout();
}
assert.eq(test.auth("sha256user", "pass"), sha256ok);
if (sha256ok) {
test.logout();
}
assert(mongod.getDB("admin").auth("admin", "pass"));
MongoRunner.stopMongod(mongod);
}
restartWithOneMech("SCRAM-SHA-1");
restartWithOneMech("SCRAM-SHA-256");