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
|
// Test auth of the explain command.
var conn = MongoRunner.runMongod({auth: ""});
var authzErrorCode = 13;
var admin = conn.getDB("admin");
admin.createUser({user: "adminUser", pwd: "pwd", roles: ["root"]});
admin.auth({user: "adminUser", pwd: "pwd"});
var db = conn.getDB("explain_auth_db");
var coll = db.explain_auth_coll;
assert.writeOK(coll.insert({_id: 1, a: 1}));
/**
* Runs explains of find, count, group, remove, and update. Checks that they either succeed or
* fail with "not authorized".
*
* Takes as input a document 'authSpec' with the following format:
* {
* find: <bool>,
* count: <bool>,
* group: <bool>,
* remove: <bool>,
* update: <bool>
* }
*
* A true value indicates that the corresponding explain should succeed, whereas a false value
* indicates that the explain command should not be authorized.
*/
function testExplainAuth(authSpec) {
var cmdResult;
function assertCmdResult(result, expectSuccess) {
if (expectSuccess) {
assert.commandWorked(result);
} else {
assert.commandFailedWithCode(result, 13);
}
}
// .find()
cmdResult = db.runCommand({explain: {find: coll.getName()}});
assertCmdResult(cmdResult, authSpec.find);
// .count()
cmdResult = db.runCommand({explain: {count: coll.getName()}});
assertCmdResult(cmdResult, authSpec.count);
// .group()
cmdResult = db.runCommand(
{explain: {group: {ns: coll.getName(), key: "a", $reduce: function() {}, initial: {}}}});
assertCmdResult(cmdResult, authSpec.group);
// .remove()
cmdResult =
db.runCommand({explain: {delete: coll.getName(), deletes: [{q: {a: 1}, limit: 1}]}});
assertCmdResult(cmdResult, authSpec.remove);
// .update()
cmdResult = db.runCommand(
{explain: {update: coll.getName(), updates: [{q: {a: 1}, u: {$set: {b: 1}}}]}});
assertCmdResult(cmdResult, authSpec.update);
}
// Create some user-defined roles which we will grant to the users below.
db.createRole({
role: "findOnly",
privileges: [{resource: {db: db.getName(), collection: coll.getName()}, actions: ["find"]}],
roles: []
});
db.createRole({
role: "updateOnly",
privileges: [{resource: {db: db.getName(), collection: coll.getName()}, actions: ["update"]}],
roles: []
});
db.createRole({
role: "removeOnly",
privileges: [{resource: {db: db.getName(), collection: coll.getName()}, actions: ["remove"]}],
roles: []
});
// Create three users:
// -- user defined role with just "find"
// -- user defined role with just "update"
// -- user defined role with just "remove"
db.createUser({user: "findOnly", pwd: "pwd", roles: ["findOnly"]});
db.createUser({user: "updateOnly", pwd: "pwd", roles: ["updateOnly"]});
db.createUser({user: "removeOnly", pwd: "pwd", roles: ["removeOnly"]});
// We're done doing test setup, so admin user should no longer be logged in.
admin.logout();
// The "find" action allows explain of read operations.
db.auth("findOnly", "pwd");
testExplainAuth({find: true, count: true, group: true, remove: false, update: false});
db.logout();
db.auth("updateOnly", "pwd");
testExplainAuth({find: false, count: false, group: false, remove: false, update: true});
db.logout();
db.auth("removeOnly", "pwd");
testExplainAuth({find: false, count: false, group: false, remove: true, update: false});
db.logout();
|