1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
/*
Exhaustive test for authorization of commands with builtin roles.
The test logic implemented here operates on the test cases defined
in jstests/auth/commands.js.
*/
load("jstests/auth/lib/commands_lib.js");
var roles = [
{key: "read", role: "read", dbname: firstDbName},
{key: "readAnyDatabase", role: "readAnyDatabase", dbname: adminDbName},
{key: "readWrite", role: "readWrite", dbname: firstDbName},
{key: "readWriteAnyDatabase", role: "readWriteAnyDatabase", dbname: adminDbName},
{key: "userAdmin", role: "userAdmin", dbname: firstDbName},
{key: "userAdminAnyDatabase", role: "userAdminAnyDatabase", dbname: adminDbName},
{key: "dbAdmin", role: "dbAdmin", dbname: firstDbName},
{key: "dbAdminAnyDatabase", role: "dbAdminAnyDatabase", dbname: adminDbName},
{key: "clusterAdmin", role: "clusterAdmin", dbname: adminDbName},
{key: "dbOwner", role: "dbOwner", dbname: firstDbName},
{key: "clusterMonitor", role: "clusterMonitor", dbname: adminDbName},
{key: "hostManager", role: "hostManager", dbname: adminDbName},
{key: "clusterManager", role: "clusterManager", dbname: adminDbName},
{key: "backup", role: "backup", dbname: adminDbName},
{key: "restore", role: "restore", dbname: adminDbName},
{key: "root", role: "root", dbname: adminDbName},
{key: "__system", role: "__system", dbname: adminDbName}
];
/**
* Parameters:
* conn -- connection, either to standalone mongod,
* or to mongos in sharded cluster
* t -- a test object from the tests array in jstests/auth/commands.js
* testcase -- the particular testcase from t to test
* r -- a role object from the "roles" array above
*
* Returns:
* An empty string on success, or an error string
* on test failure.
*/
function testProperAuthorization(conn, t, testcase, r) {
var out = "";
var runOnDb = conn.getDB(testcase.runOnDb);
authCommandsLib.setup(conn, t, runOnDb);
assert(r.db.auth("user|" + r.role, "password"));
var res = runOnDb.runCommand(t.command);
if (testcase.roles[r.role]) {
if (res.ok == 0 && res.code == authErrCode) {
out = "expected authorization success" +
" but received " + tojson(res) +
" on db " + testcase.runOnDb +
" with role " + r.key;
}
else if (res.ok == 0 && !testcase.expectFail && res.code != commandNotSupportedCode) {
// don't error if the test failed with code commandNotSupported since
// some storage engines (e.g wiredTiger) don't support some commands (e.g. touch)
out = "command failed with " + tojson(res) +
" on db " + testcase.runOnDb +
" with role " + r.key;
}
// test can provide a function that will run if
// the command completed successfully
else if (testcase.onSuccess) {
testcase.onSuccess(res);
}
}
else {
if (res.ok == 1 || (res.ok == 0 && res.code != authErrCode)) {
out = "expected authorization failure" +
" but received result " + tojson(res) +
" on db " + testcase.runOnDb +
" with role " + r.key;
}
}
r.db.logout();
authCommandsLib.teardown(conn, t, runOnDb);
return out;
}
function runOneTest(conn, t) {
var failures = [];
for (var i = 0; i < t.testcases.length; i++) {
var testcase = t.testcases[i];
if (!("roles" in testcase)) {
continue;
}
for (var j = 0; j < roles.length; j++) {
var msg = testProperAuthorization(conn, t, testcase, roles[j]);
if (msg) {
failures.push(t.testname + ": " + msg);
}
}
}
return failures;
}
function createUsers(conn) {
var adminDb = conn.getDB(adminDbName);
adminDb.createUser({
user: "admin",
pwd: "password",
roles: ["__system"]
});
assert(adminDb.auth("admin", "password"));
for (var i = 0; i < roles.length; i++) {
r = roles[i];
r.db = conn.getDB(r.dbname);
r.db.createUser({user: "user|" + r.role, pwd: "password", roles: [r.role]});
}
adminDb.logout();
}
/*
* Makes sure that none of the test cases reference roles
* that aren't part of the global "roles" array.
*/
function checkForNonExistentRoles() {
var tests = authCommandsLib.tests;
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
for (var j = 0; j < test.testcases.length; j++) {
var testcase = test.testcases[j];
for (role in testcase.roles) {
var roleExists = false;
for (var k = 0; k < roles.length; k++) {
if (roles[k].role === role) {
roleExists = true;
break;
}
}
assert(roleExists, "Role " + role + " found in test: " + test.testname +
", but doesn't exist in roles array");
}
}
}
}
var opts = {
auth:"",
enableExperimentalIndexStatsCmd: "",
enableExperimentalStorageDetailsCmd: ""
}
var impls = {
createUsers: createUsers,
runOneTest: runOneTest
}
checkForNonExistentRoles();
// run all tests standalone
var conn = MongoRunner.runMongod(opts);
authCommandsLib.runTests(conn, impls);
MongoRunner.stopMongod(conn);
// run all tests sharded
conn = new ShardingTest({
shards: 2,
mongos: 1,
keyFile: "jstests/libs/key1",
other: { shardOptions: opts }
});
authCommandsLib.runTests(conn, impls);
conn.stop();
|