228 lines
10 KiB
JavaScript
228 lines
10 KiB
JavaScript
// Test creation of local users and roles for multitenancy.
|
|
|
|
import {runCommandWithSecurityToken} from "jstests/libs/multitenancy_utils.js";
|
|
|
|
function setup(conn) {
|
|
const admin = conn.getDB('admin');
|
|
assert.commandWorked(
|
|
admin.runCommand({createUser: 'admin', pwd: 'admin', roles: ['__system']}));
|
|
assert(admin.auth('admin', 'admin'));
|
|
}
|
|
|
|
function runTests(conn, tenant, multitenancySupport) {
|
|
if (tenant == null && multitenancySupport) {
|
|
// When multitenancySupport is enabled, requests are expected to contain a tenant, so do not
|
|
// run these tests when tenant is null and multitenancySupport is enabled.
|
|
return;
|
|
}
|
|
|
|
const expectSuccess = (tenant === null) || (multitenancySupport && TestData.enableTestCommands);
|
|
jsTest.log("Runing test: " + tojson({tenant: tenant, multi: multitenancySupport}));
|
|
|
|
function checkSuccess(result) {
|
|
if (expectSuccess) {
|
|
return assert.commandWorked(result);
|
|
} else {
|
|
assert.commandFailedWithCode(result, ErrorCodes.InvalidOptions);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const admin = conn.getDB('admin');
|
|
const test = conn.getDB('test');
|
|
const token = tenant === null ? undefined : _createTenantToken({tenant: tenant});
|
|
|
|
function runFindCmdWithTenant(db, collection, filter) {
|
|
let result = [];
|
|
let cmdRes = assert.commandWorked(runCommandWithSecurityToken(
|
|
token, db, {find: collection, filter: filter, batchSize: 0}));
|
|
result = result.concat(cmdRes.cursor.firstBatch);
|
|
|
|
let cursorId = cmdRes.cursor.id;
|
|
while (cursorId != 0) {
|
|
cmdRes = assert.commandWorked(runCommandWithSecurityToken(
|
|
token, db, {getMore: cursorId, collection: collection, batchSize: 1}));
|
|
result = result.concat(cmdRes.cursor.nextBatch);
|
|
cursorId = cmdRes.cursor.id;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function findTenantRoles(filter) {
|
|
return runFindCmdWithTenant(admin, "system.roles", filter);
|
|
}
|
|
|
|
function findTenantUsers(filter) {
|
|
return runFindCmdWithTenant(admin, "system.users", filter);
|
|
}
|
|
|
|
function validateCounts(expectUsers, expectRoles) {
|
|
const filter = {db: 'test'};
|
|
const admin = conn.getDB('admin');
|
|
|
|
if (!expectSuccess) {
|
|
expectUsers = expectRoles = 0;
|
|
}
|
|
|
|
// usersInfo/rolesInfo commands return expected data.
|
|
const usersInfo =
|
|
assert.commandWorked(runCommandWithSecurityToken(token, test, {usersInfo: 1})).users;
|
|
const rolesInfo = assert
|
|
.commandWorked(runCommandWithSecurityToken(
|
|
token, test, {rolesInfo: 1, showPrivileges: true}))
|
|
.roles;
|
|
assert.eq(usersInfo.length, expectUsers, tojson(usersInfo));
|
|
assert.eq(rolesInfo.length, expectRoles, tojson(rolesInfo));
|
|
|
|
if (tenant) {
|
|
// Look for users/roles in tenant specific collections directly.
|
|
const tenantUsers = findTenantUsers(filter);
|
|
const tenantRoles = findTenantRoles(filter);
|
|
|
|
assert.eq(tenantUsers.length, expectUsers, tojson(tenantUsers));
|
|
assert.eq(tenantRoles.length, expectRoles, tojson(tenantRoles));
|
|
|
|
// Found users/roles in tenant, don't look for them in base collections.
|
|
expectUsers = expectRoles = 0;
|
|
}
|
|
|
|
// Check base system collections, generally should be empty, unless we're in no-tenant mode.
|
|
const systemUsers = admin.system.users.find(filter).toArray();
|
|
const systemRoles = admin.system.roles.find(filter).toArray();
|
|
assert.eq(systemUsers.length, expectUsers, tojson(systemUsers));
|
|
assert.eq(systemRoles.length, expectRoles, tojson(systemRoles));
|
|
}
|
|
|
|
// createUser/createRole
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {createUser: 'user1', 'pwd': 'pwd', roles: []}));
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {createRole: 'role1', roles: [], privileges: []}));
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {createRole: 'role2', roles: ['role1'], privileges: []}));
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {createRole: 'role3', roles: [{db: 'test', role: 'role1'}], privileges: []}));
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {createUser: 'user2', 'pwd': 'pwd', roles: ['role2', 'role3']}));
|
|
|
|
const rwMyColl_privs = [{
|
|
resource: {db: 'test', collection: 'myColl'},
|
|
actions: ['find', 'insert', 'remove', 'update']
|
|
}];
|
|
const myCollUser_roles = [{role: 'rwMyColl', db: 'test'}];
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {createRole: 'rwMyColl', roles: [], privileges: rwMyColl_privs}));
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {createUser: 'myCollUser', pwd: 'pwd', roles: myCollUser_roles}));
|
|
validateCounts(3, 4);
|
|
|
|
if (tenant && expectSuccess) {
|
|
const myCollUser = findTenantUsers({_id: 'test.myCollUser'})[0];
|
|
assert.eq(tojson(myCollUser.roles), tojson(myCollUser_roles), tojson(myCollUser));
|
|
const rwMyColl = findTenantRoles({_id: 'test.rwMyColl'})[0];
|
|
assert.eq(tojson(rwMyColl.privileges), tojson(rwMyColl_privs), tojson(rwMyColl));
|
|
const role2 = findTenantRoles({_id: 'test.role2'})[0];
|
|
assert.eq(tojson(role2.roles), tojson([{role: 'role1', db: 'test'}]), tojson(role2));
|
|
const role3 = findTenantRoles({_id: 'test.role3'})[0];
|
|
assert.eq(tojson(role3.roles), tojson([{role: 'role1', db: 'test'}]), tojson(role3));
|
|
}
|
|
|
|
// grant/revoke privileges
|
|
const rwMyColl_addPrivs =
|
|
[{resource: {db: 'test', collection: 'otherColl'}, actions: ['find']}];
|
|
checkSuccess(runCommandWithSecurityToken(
|
|
token, test, {grantPrivilegesToRole: 'rwMyColl', privileges: rwMyColl_addPrivs}));
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {
|
|
revokePrivilegesFromRole: 'rwMyColl',
|
|
privileges: [{resource: {db: 'test', collection: 'myColl'}, actions: ['find']}]
|
|
}));
|
|
validateCounts(3, 4);
|
|
|
|
if (tenant && expectSuccess) {
|
|
const rwMyColl_expectPrivs = [
|
|
{resource: {db: 'test', collection: 'myColl'}, actions: ['insert', 'remove', 'update']},
|
|
{resource: {db: 'test', collection: 'otherColl'}, actions: ['find']}
|
|
];
|
|
const rwMyColl = findTenantRoles({_id: 'test.rwMyColl'})[0];
|
|
assert.eq(tojson(rwMyColl.privileges), tojson(rwMyColl_expectPrivs), tojson(rwMyColl));
|
|
}
|
|
|
|
// Grant/Revoke Roles to/fromfrom User/Role
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {grantRolesToUser: 'user1', roles: ['role1']}));
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {revokeRolesFromUser: 'user2', roles: ['role2']}));
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {grantRolesToRole: 'role1', roles: ['rwMyColl']}));
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {revokeRolesFromRole: 'role3', roles: ['role1']}));
|
|
validateCounts(3, 4);
|
|
|
|
if (tenant && expectSuccess) {
|
|
const user1 = findTenantUsers({_id: 'test.user1'})[0];
|
|
assert.eq(tojson(user1.roles), tojson([{role: 'role1', db: 'test'}]), tojson(user1));
|
|
const user2 = findTenantUsers({_id: 'test.user2'})[0];
|
|
assert.eq(tojson(user2.roles), tojson([{role: 'role3', db: 'test'}]), tojson(user2));
|
|
|
|
const role1 = findTenantRoles({_id: 'test.role1'})[0];
|
|
assert.eq(tojson(role1.roles), tojson([{role: 'rwMyColl', db: 'test'}]), tojson(role1));
|
|
const role3 = findTenantRoles({_id: 'test.role3'})[0];
|
|
assert.eq(tojson(role3.roles), tojson([]), tojson(role3));
|
|
}
|
|
|
|
// updateUser/updateRole
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {updateUser: 'user1', roles: ['role2']}));
|
|
checkSuccess(
|
|
runCommandWithSecurityToken(token, test, {updateRole: 'role2', roles: ['rwMyColl']}));
|
|
validateCounts(3, 4);
|
|
|
|
if (tenant && expectSuccess) {
|
|
const user1 = findTenantUsers({_id: 'test.user1'})[0];
|
|
assert.eq(tojson(user1.roles), tojson([{role: 'role2', db: 'test'}]), tojson(user1));
|
|
const role2 = findTenantRoles({_id: 'test.role2'})[0];
|
|
assert.eq(tojson(role2.roles), tojson([{role: 'rwMyColl', db: 'test'}]), tojson(role2));
|
|
}
|
|
|
|
// dropUser/dropRole
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {dropRole: 'role2'}));
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {dropUser: 'myCollUser'}));
|
|
validateCounts(2, 3);
|
|
|
|
if (tenant && expectSuccess) {
|
|
// role2 should have been revoked from user1 during drop,.
|
|
const user1 = findTenantUsers({_id: 'test.user1'})[0];
|
|
assert.eq(tojson(user1.roles), tojson([]), tojson(user1));
|
|
assert.eq(0, findTenantUsers({_id: 'test.myCollUser'}).length);
|
|
assert.eq(0, findTenantRoles({_id: 'test.role2'}).length);
|
|
}
|
|
|
|
// Cleanup
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {dropAllUsersFromDatabase: 1}));
|
|
checkSuccess(runCommandWithSecurityToken(token, test, {dropAllRolesFromDatabase: 1}));
|
|
validateCounts(0, 0);
|
|
}
|
|
|
|
// This isn't relevant to this test, but requires enableTestCommands, which we want to frob.
|
|
TestData.roleGraphInvalidationIsFatal = false;
|
|
|
|
function spanOptions(cb) {
|
|
[true].forEach(function(enableTestCommands) {
|
|
TestData.enableTestCommands = enableTestCommands;
|
|
[true].forEach(function(multitenancySupport) {
|
|
jsTest.log(
|
|
{enableTestCommands: enableTestCommands, multitenancySupport: multitenancySupport});
|
|
cb({multitenancySupport: multitenancySupport});
|
|
});
|
|
});
|
|
}
|
|
|
|
spanOptions(function(setParams) {
|
|
const standalone = MongoRunner.runMongod({auth: "", setParameter: setParams});
|
|
jsTest.log('Standalone started');
|
|
setup(standalone);
|
|
runTests(standalone, null, setParams.multitenancySupport);
|
|
runTests(standalone, ObjectId(), setParams.multitenancySupport);
|
|
MongoRunner.stopMongod(standalone);
|
|
});
|