mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 01:21:03 +01:00
168 lines
7.2 KiB
JavaScript
168 lines
7.2 KiB
JavaScript
// Auth tests for the listDatabases command.
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
function runTest(mongod) {
|
|
const admin = mongod.getDB('admin');
|
|
admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles});
|
|
assert(admin.auth('admin', 'pass'));
|
|
|
|
// Establish db0..db7
|
|
for (let i = 0; i < 8; ++i) {
|
|
mongod.getDB('db' + i).foo.insert({bar: "baz"});
|
|
}
|
|
mongod.getDB("db0").baz.insert({x: "y"});
|
|
mongod.getDB("db2").baz.insert({x: "y"});
|
|
|
|
admin.createRole({
|
|
role: 'dbLister',
|
|
privileges: [{resource: {cluster: true}, actions: ['listDatabases']}],
|
|
roles: []
|
|
});
|
|
|
|
admin.createRole({
|
|
role: 'specificCollection',
|
|
privileges: [{resource: {db: "db0", collection: "baz"}, actions: ['find']}],
|
|
roles: []
|
|
});
|
|
|
|
admin.createRole({
|
|
role: 'sharedNameCollections',
|
|
privileges: [{resource: {db: "", collection: "baz"}, actions: ['find']}],
|
|
roles: []
|
|
});
|
|
|
|
// Make db0, db2, db4, db6 readable to user1 abd user3.
|
|
// Make db0, db1, db2, db3 read/writable to user 2 and user3.
|
|
function makeRole(perm, dbNum) {
|
|
return {role: perm, db: ("db" + dbNum)};
|
|
}
|
|
const readEven = [0, 2, 4, 6].map(function(i) {
|
|
return makeRole("read", i);
|
|
});
|
|
const readWriteLow = [0, 1, 2, 3].map(function(i) {
|
|
return makeRole("readWrite", i);
|
|
});
|
|
admin.createUser({user: 'user1', pwd: 'pass', roles: readEven});
|
|
admin.createUser({user: 'user2', pwd: 'pass', roles: readWriteLow});
|
|
admin.createUser({user: 'user3', pwd: 'pass', roles: readEven.concat(readWriteLow)});
|
|
|
|
// Make db4 readable by user 4, and let them list all dbs.
|
|
// Make db5 readable by user 5, and let them list all dbs.
|
|
// Make collection baz in db0 findable by user6, and let them list db0.
|
|
// Make all baz collections findable by user7, and let them list all dbs.
|
|
admin.createUser({user: 'user4', pwd: 'pass', roles: [makeRole('read', 4), 'dbLister']});
|
|
admin.createUser({user: 'user5', pwd: 'pass', roles: [makeRole('read', 5), 'dbLister']});
|
|
admin.createUser({user: 'user6', pwd: 'pass', roles: ['specificCollection']});
|
|
admin.createUser({user: 'user7', pwd: 'pass', roles: ['sharedNameCollections']});
|
|
admin.logout();
|
|
|
|
const admin_dbs = ["admin", "db0", "db1", "db2", "db3", "db4", "db5", "db6", "db7"];
|
|
|
|
[{user: "user1", dbs: ["db0", "db2", "db4", "db6"]},
|
|
{user: "user2", dbs: ["db0", "db1", "db2", "db3"]},
|
|
{user: "user3", dbs: ["db0", "db1", "db2", "db3", "db4", "db6"]},
|
|
{user: "user4", dbs: admin_dbs, authDbs: ["db4"]},
|
|
{user: "user5", dbs: admin_dbs, authDbs: ["db5"]},
|
|
{user: "user6", dbs: ["db0"]},
|
|
{user: "user7", dbs: admin_dbs},
|
|
{user: "admin", dbs: admin_dbs, authDbs: admin_dbs},
|
|
].forEach(function(test) {
|
|
function filterSpecial(db) {
|
|
// Returning of local/config varies with sharding/mobile/etc..
|
|
// Ignore these for simplicity.
|
|
return (db !== 'local') && (db !== 'config');
|
|
}
|
|
|
|
// Invoking {listDatabases: 1} directly.
|
|
function tryList(cmd, expect_dbs) {
|
|
const dbs = assert.commandWorked(admin.runCommand(cmd));
|
|
assert.eq(dbs.databases
|
|
.map(function(db) {
|
|
return db.name;
|
|
})
|
|
.filter(filterSpecial)
|
|
.sort(),
|
|
expect_dbs,
|
|
test.user + " permissions");
|
|
}
|
|
|
|
admin.auth(test.user, 'pass');
|
|
tryList({listDatabases: 1}, test.dbs);
|
|
tryList({listDatabases: 1, authorizedDatabases: true}, test.authDbs || test.dbs);
|
|
|
|
if (test.authDbs) {
|
|
tryList({listDatabases: 1, authorizedDatabases: false}, test.dbs);
|
|
} else {
|
|
// Users without listDatabases cluster perm may not
|
|
// request authorizedDatabases: false.
|
|
assert.throws(tryList, [{listDatabases: 1, authorizedDatabases: false}, test.dbs]);
|
|
}
|
|
|
|
// Test using shell helper Mongo.getDBs().
|
|
assert.eq(mongod.getDBs(undefined, {}, true).filter(filterSpecial),
|
|
test.dbs,
|
|
"Shell helper speaking to same version");
|
|
if (test.user !== 'admin' && test.user !== "user7") {
|
|
// Admin and user7 don't have an explicit list of DBs to parse.
|
|
assert.eq(mongod._getDatabaseNamesFromPrivileges(), test.authDbs || test.dbs);
|
|
|
|
// Test (non-admin) call to Mongo.getDBs() on a < 4.0 MongoD
|
|
// by injecting a command failure into Mongo.adminCommand().
|
|
// This will allow us to resemble a < 4.0 server.
|
|
const adminCommandFunction = mongod.adminCommand;
|
|
const adminCommandMethod = adminCommandFunction.bind(mongod);
|
|
|
|
try {
|
|
mongod.adminCommand = function(cmd) {
|
|
if (cmd.hasOwnProperty('listDatabases')) {
|
|
return {
|
|
ok: 0,
|
|
errmsg: 'Stubbed command failure: ' + tojson(cmd),
|
|
code: ErrorCodes.Unauthorized,
|
|
codeName: 'Unauthorized'
|
|
};
|
|
}
|
|
return adminCommandMethod(cmd);
|
|
};
|
|
// Command fails, but we dispatch via _getDatabaseNamesFromPrivileges().
|
|
assert.eq(mongod.getDBs().databases.map(function(x) {
|
|
return x.name;
|
|
}),
|
|
test.authDbs || test.dbs);
|
|
|
|
// Still dispatches with explicit nameOnly===true, returns only names.
|
|
assert.eq(mongod.getDBs(undefined, undefined, true), test.authDbs || test.dbs);
|
|
|
|
// Command fails and unable to dispatch because nameOnly !== true.
|
|
assert.throws(() => mongod.getDBs(undefined, undefined, false));
|
|
|
|
// Command fails and unable to dispatch because filter is not empty.
|
|
assert.throws(() => mongod.getDBs(undefined, {name: 'foo'}));
|
|
} finally {
|
|
mongod.adminCommand = adminCommandFunction;
|
|
}
|
|
}
|
|
|
|
admin.logout();
|
|
});
|
|
}
|
|
|
|
const mongod = MongoRunner.runMongod({auth: ""});
|
|
runTest(mongod);
|
|
MongoRunner.stopMongod(mongod);
|
|
|
|
if (jsTest.options().storageEngine !== "mobile") {
|
|
// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
|
|
const st = new ShardingTest({
|
|
shards: 1,
|
|
mongos: 1,
|
|
config: 1,
|
|
other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false}
|
|
});
|
|
runTest(st.s0);
|
|
st.stop();
|
|
}
|
|
})();
|