/** * This tests that all the different commands for user manipulation all work properly for all valid * forms of input. */ export function runAllUserManagementCommandsTests(conn, writeConcern) { function hasAuthzError(result) { assert(result instanceof WriteCommandError); assert.eq(ErrorCodes.Unauthorized, result.code); } const admin = conn.getDB("admin"); admin.createUser({user: "admin", pwd: "pwd", roles: ["root"]}, writeConcern); assert(admin.auth("admin", "pwd")); admin.createUser( { user: "userAdmin", pwd: "pwd", roles: ["userAdminAnyDatabase"], customData: {userAdmin: true}, }, writeConcern, ); admin.logout(); const userAdminConn = new Mongo(conn.host); const userAdmin = userAdminConn.getDB("admin"); assert(userAdmin.auth("userAdmin", "pwd")); const testUserAdmin = userAdminConn.getDB("test"); testUserAdmin.createRole( { role: "testRole", roles: [], privileges: [{resource: {db: "test", collection: ""}, actions: ["viewRole"]}], }, writeConcern, ); userAdmin.createRole( { role: "adminRole", roles: [], privileges: [{resource: {cluster: true}, actions: ["connPoolSync"]}], }, writeConcern, ); const db = conn.getDB("test"); // At this point there are 2 handles to the "test" database in use - "testUserAdmin" and "db". // "testUserAdmin" is on a connection which has been auth'd as a user with the // 'userAdminAnyDatabase' role. This will be used for manipulating the user defined roles // used in the test. "db" is a handle to the test database on a connection that has not // yet been authenticated as anyone. This is the connection that will be used to log in as // various users and test that their access control is correct. (function testCreateUser() { jsTestLog("Testing createUser"); testUserAdmin.createUser( { user: "spencer", pwd: "pwd", customData: {zipCode: 10028}, roles: ["readWrite", "testRole", {role: "adminRole", db: "admin"}], }, writeConcern, ); testUserAdmin.createUser({user: "andy", pwd: "pwd", roles: []}, writeConcern); const user = testUserAdmin.getUser("spencer"); assert.eq(10028, user.customData.zipCode); assert(db.auth("spencer", "pwd")); assert.commandWorked(db.foo.insert({a: 1})); assert.eq(1, db.foo.findOne().a); assert.doesNotThrow(function () { db.getRole("testRole"); }); assert.commandWorked(db.adminCommand("connPoolSync")); db.logout(); assert(db.auth("andy", "pwd")); hasAuthzError(db.foo.insert({a: 1})); assert.throws(function () { db.foo.findOne(); }); assert.throws(function () { db.getRole("testRole"); }); db.logout(); })(); (function testUpdateUser() { jsTestLog("Testing updateUser"); testUserAdmin.updateUser("spencer", {pwd: "password", customData: {}}, writeConcern); const user1 = testUserAdmin.getUser("spencer"); assert.eq(null, user1.customData.zipCode); assert(!db.auth("spencer", "pwd")); assert(db.auth("spencer", "password")); testUserAdmin.updateUser("spencer", {customData: {zipCode: 10036}, roles: ["read", "testRole"]}, writeConcern); const user = testUserAdmin.getUser("spencer"); assert.eq(10036, user.customData.zipCode); hasAuthzError(db.foo.insert({a: 1})); assert.eq(1, db.foo.findOne().a); assert.eq(1, db.foo.count()); assert.doesNotThrow(function () { db.getRole("testRole"); }); assert.commandFailedWithCode(db.adminCommand("connPoolSync"), ErrorCodes.Unauthorized); testUserAdmin.updateUser("spencer", {roles: ["readWrite", {role: "adminRole", db: "admin"}]}, writeConcern); assert.commandWorked(db.foo.update({}, {$inc: {a: 1}})); assert.eq(2, db.foo.findOne().a); assert.eq(1, db.foo.count()); assert.throws(function () { db.getRole("testRole"); }); assert.commandWorked(db.adminCommand("connPoolSync")); })(); (function testGrantRolesToUser() { jsTestLog("Testing grantRolesToUser"); assert.commandFailedWithCode(db.runCommand({collMod: "foo"}), ErrorCodes.Unauthorized); testUserAdmin.grantRolesToUser( "spencer", ["readWrite", "dbAdmin", {role: "readWrite", db: "test"}, {role: "testRole", db: "test"}, "readWrite"], writeConcern, ); assert.commandWorked(db.runCommand({collMod: "foo"})); assert.commandWorked(db.foo.update({}, {$inc: {a: 1}})); assert.eq(3, db.foo.findOne().a); assert.eq(1, db.foo.count()); assert.doesNotThrow(function () { db.getRole("testRole"); }); assert.commandWorked(db.adminCommand("connPoolSync")); })(); (function testRevokeRolesFromUser() { jsTestLog("Testing revokeRolesFromUser"); testUserAdmin.revokeRolesFromUser( "spencer", [ "readWrite", {role: "dbAdmin", db: "test2"}, // role user doesnt have "testRole", ], writeConcern, ); assert.commandWorked(db.runCommand({collMod: "foo"})); hasAuthzError(db.foo.update({}, {$inc: {a: 1}})); assert.throws(function () { db.foo.findOne(); }); assert.throws(function () { db.getRole("testRole"); }); assert.commandWorked(db.adminCommand("connPoolSync")); testUserAdmin.revokeRolesFromUser("spencer", [{role: "adminRole", db: "admin"}], writeConcern); hasAuthzError(db.foo.update({}, {$inc: {a: 1}})); assert.throws(function () { db.foo.findOne(); }); assert.throws(function () { db.getRole("testRole"); }); assert.commandFailedWithCode(db.adminCommand("connPoolSync"), ErrorCodes.Unauthorized); })(); (function testUsersInfo() { // Helper functions for the expected output of usersInfo, depending on the variant used. function assertNoExtraInfo(user) { assert(!user.credentials); assertNoPrivilegesOrAuthRestrictions(user); } function assertNoPrivilegesOrAuthRestrictions(user) { assert(!user.inheritedRoles); assert(!user.inheritedPrivileges); assert(!user.inheritedAuthenticationRestrictions); assert(!user.authenticationRestrictions); } function assertShowCredentials(user) { assert(user.credentials["SCRAM-SHA-1"]); assert(user.credentials["SCRAM-SHA-256"]); } function assertShowPrivileges( user, expectedInheritedRolesLength, expectedInheritedPrivilegesLength, expectedInheritedAuthenticationRestrictionsLength, ) { assert.eq(expectedInheritedRolesLength, user.inheritedRoles.length); assert.eq(expectedInheritedPrivilegesLength, user.inheritedPrivileges.length); assert.eq( expectedInheritedAuthenticationRestrictionsLength, user.inheritedAuthenticationRestrictions.length, ); } function assertShowAuthenticationRestrictions( user, expectedInheritedRolesLength, expectedInheritedPrivilegesLength, expectedInheritedAuthenticationRestrictionsLength, expectedAuthenticationRestrictionsLength, ) { assertShowPrivileges( user, expectedInheritedRolesLength, expectedInheritedPrivilegesLength, expectedInheritedAuthenticationRestrictionsLength, ); assert.eq(expectedAuthenticationRestrictionsLength, user.authenticationRestrictions.length); } jsTestLog("Testing usersInfo"); jsTestLog("Running exact usersInfo with default options on username only"); let res = testUserAdmin.runCommand({usersInfo: "spencer"}); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); assertNoExtraInfo(res.users[0]); jsTestLog("Running exact usersInfo with default options on username and db"); res = testUserAdmin.runCommand({usersInfo: {user: "spencer", db: "test"}}); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); assertNoExtraInfo(res.users[0]); jsTestLog("Running exact usersInfo on single user with showCredentials set to true"); res = testUserAdmin.runCommand({usersInfo: {user: "spencer", db: "test"}, showCredentials: true}); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); assertShowCredentials(res.users[0]); assertNoPrivilegesOrAuthRestrictions(res.users[0]); jsTestLog("Running exact usersInfo on single user with showPrivileges set to true"); res = testUserAdmin.runCommand({usersInfo: {user: "spencer", db: "test"}, showPrivileges: true}); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); assert(!res.users[0].credentials); assertShowPrivileges(res.users[0], 1, 2, 0); assert(!res.users[0].authenticationRestrictions); jsTestLog("Running exact usersInfo on single user with showAuthenticationRestrictions set to true"); res = testUserAdmin.runCommand({ usersInfo: {user: "spencer", db: "test"}, showAuthenticationRestrictions: true, }); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); assert(!res.users[0].credentials); assertShowAuthenticationRestrictions(res.users[0], 1, 2, 0, 0); jsTestLog("Running exact usersInfo on single user with showCustomData set to false"); res = testUserAdmin.runCommand({usersInfo: {user: "spencer", db: "test"}, showCustomData: false}); printjson(res); assert.eq(1, res.users.length); assert(!res.users[0].customData); assertNoExtraInfo(res.users[0]); // This should trigger the authorization user cache. jsTestLog("Running exact usersInfo on single user with all non-default options set"); res = testUserAdmin.runCommand({ usersInfo: {user: "spencer", db: "test"}, showCredentials: true, showPrivileges: true, showAuthenticationRestrictions: true, showCustomData: false, }); printjson(res); assert.eq(1, res.users.length); assert(!res.users[0].customData); assertShowCredentials(res.users[0]); assertShowAuthenticationRestrictions(res.users[0], 1, 2, 0, 0); // UsersInfo results are ordered alphabetically by user field then db field, // not by user insertion order jsTestLog("Running exact usersInfo on multiple users with default options"); res = testUserAdmin.runCommand({usersInfo: ["spencer", {user: "userAdmin", db: "admin"}]}); printjson(res); assert.eq(2, res.users.length); assert.eq("spencer", res.users[0].user); assert.eq(10036, res.users[0].customData.zipCode); assert.eq("userAdmin", res.users[1].user); assert(res.users[1].customData.userAdmin); res.users.forEach((user) => { assertNoExtraInfo(user); }); jsTestLog("Running exact usersInfo on multiple users with showCredentials set to true"); res = testUserAdmin.runCommand({ usersInfo: ["spencer", {user: "userAdmin", db: "admin"}], showCredentials: true, }); printjson(res); assert.eq(2, res.users.length); assert.eq("spencer", res.users[0].user); assert.eq(10036, res.users[0].customData.zipCode); assert.eq("userAdmin", res.users[1].user); assert(res.users[1].customData.userAdmin); res.users.forEach((user) => { assertShowCredentials(user); assertNoPrivilegesOrAuthRestrictions(user); }); jsTestLog("Running exact usersInfo on multiple users with showPrivileges set to true"); res = testUserAdmin.runCommand({ usersInfo: ["spencer", {user: "userAdmin", db: "admin"}], showPrivileges: true, }); printjson(res); assert.eq(2, res.users.length); assert.eq("spencer", res.users[0].user); assert.eq(10036, res.users[0].customData.zipCode); assert(!res.users[0].credentials); assertShowPrivileges(res.users[0], 1, 2, 0); assert(!res.users[0].authenticationRestrictions); assert.eq("userAdmin", res.users[1].user); assert(res.users[1].customData.userAdmin); assert(!res.users[1].credentials); assertShowPrivileges(res.users[1], 1, 9, 0); assert(!res.users[1].authenticationRestrictions); jsTestLog("Running exact usersInfo on multiple users with showAuthenticationRestrictions set to true"); res = testUserAdmin.runCommand({ usersInfo: ["spencer", {user: "userAdmin", db: "admin"}], showAuthenticationRestrictions: true, }); printjson(res); assert.eq(2, res.users.length); assert.eq("spencer", res.users[0].user); assert.eq(10036, res.users[0].customData.zipCode); assert(!res.users[0].credentials); assertShowAuthenticationRestrictions(res.users[0], 1, 2, 0, 0); assert.eq("userAdmin", res.users[1].user); assert(res.users[1].customData.userAdmin); assert(!res.users[1].credentials); assertShowAuthenticationRestrictions(res.users[1], 1, 9, 0, 0); // This should also trigger the authorization user cache. jsTestLog("Running exact usersInfo on multiple users with all non-default options set"); res = testUserAdmin.runCommand({ usersInfo: ["spencer", {user: "userAdmin", db: "admin"}], showCredentials: true, showPrivileges: true, showAuthenticationRestrictions: true, showCustomData: false, }); printjson(res); assert.eq(2, res.users.length); assert.eq("spencer", res.users[0].user); assert(!res.users[0].customData); assertShowAuthenticationRestrictions(res.users[0], 1, 2, 0, 0); assert.eq("userAdmin", res.users[1].user); assert(!res.users[1].customData); assertShowAuthenticationRestrictions(res.users[1], 1, 9, 0, 0); res.users.forEach((user) => { assertShowCredentials(user); }); jsTestLog("Running non-exact usersInfo on current db with all default options set"); res = testUserAdmin.runCommand({usersInfo: 1}); assert.eq(2, res.users.length); assert.eq("andy", res.users[0].user); assert.eq("spencer", res.users[1].user); assert(!res.users[0].customData); assert.eq(10036, res.users[1].customData.zipCode); // showPrivileges and showAuthenticationRestrictions should not be allowed on non-exact // usersInfo queries. assert.commandFailed(testUserAdmin.runCommand({usersInfo: 1, showPrivileges: true})); assert.commandFailed(testUserAdmin.runCommand({usersInfo: 1, showAuthenticationRestrictions: true})); // showCredentials and showCustomData should be allowed on non-exact usersInfo queries. jsTestLog( "Running non-exact usersInfo on current db with showCredentials and showCustomData set to non-defaults", ); res = testUserAdmin.runCommand({usersInfo: 1, showCredentials: true, showCustomData: false}); printjson(res); assert.eq(2, res.users.length); assert.eq("andy", res.users[0].user); assert.eq("spencer", res.users[1].user); res.users.forEach((user) => { assertShowCredentials(user); assert(!user.customData); }); res = testUserAdmin.runCommand({usersInfo: {forAllDBs: true}}); printjson(res); assert.eq(4, res.users.length); assert.eq("admin", res.users[0].user); assert.eq("andy", res.users[1].user); assert.eq("spencer", res.users[2].user); assert.eq("userAdmin", res.users[3].user); // showPrivileges and showAuthenticationRestrictions should not be allowed on non-exact // usersInfo queries. assert.commandFailed(testUserAdmin.runCommand({usersInfo: {forAllDBs: true}, showPrivileges: true})); assert.commandFailed( testUserAdmin.runCommand({usersInfo: {forAllDBs: true}, showAuthenticationRestrictions: true}), ); // showCredentials and showCustomData should be allowed on non-exact usersInfo queries. res = testUserAdmin.runCommand({usersInfo: {forAllDBs: true}, showCredentials: true, showCustomData: false}); printjson(res); assert.eq(4, res.users.length); assert.eq("admin", res.users[0].user); assert.eq("andy", res.users[1].user); assert.eq("spencer", res.users[2].user); assert.eq("userAdmin", res.users[3].user); res.users.forEach((user) => { assertShowCredentials(user); assert(!user.customData); }); })(); (function testDropUser() { jsTestLog("Testing dropUser"); assert(db.auth("spencer", "password")); db.logout(); assert(db.auth("andy", "pwd")); testUserAdmin.dropUser("spencer", writeConcern); assert(!db.auth("spencer", "password")); assert(db.auth("andy", "pwd")); db.logout(); assert.eq(1, testUserAdmin.getUsers().length); })(); (function testDropAllUsersFromDatabase() { jsTestLog("Testing dropAllUsersFromDatabase"); assert.eq(1, testUserAdmin.getUsers().length); assert(db.auth("andy", "pwd")); db.logout(); testUserAdmin.dropAllUsers(writeConcern); assert(!db.auth("andy", "pwd")); assert.eq(0, testUserAdmin.getUsers().length); })(); }