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
|
/**
* This tests that user defined roles actually grant users the ability to perform the actions they
* should, and that changing the privileges assigned to roles changes the access granted to the user
*/
function runTest(conn) {
var authzErrorCode = 13;
var hasAuthzError = function(result) {
assert(result instanceof WriteCommandError);
assert.eq(authzErrorCode, result.code);
};
conn.getDB('admin').createUser({user: 'admin', pwd: 'pwd', roles: ['root']});
conn.getDB('admin').auth('admin', 'pwd');
conn.getDB('admin').createUser(
{user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase']});
conn.getDB('admin').logout();
var userAdminConn = new Mongo(conn.host);
var adminUserAdmin = userAdminConn.getDB('admin');
adminUserAdmin.auth('userAdmin', 'pwd');
adminUserAdmin.createRole({role: 'adminRole', privileges: [], roles: []});
var testUserAdmin = userAdminConn.getDB('test');
testUserAdmin.createRole({role: 'testRole1', privileges: [], roles: []});
testUserAdmin.createRole({role: 'testRole2', privileges: [], roles: ['testRole1']});
testUserAdmin.createUser(
{user: 'testUser', pwd: 'pwd', roles: ['testRole2', {role: 'adminRole', db: 'admin'}]});
var testDB = conn.getDB('test');
assert(testDB.auth('testUser', 'pwd'));
// At this point there are 3 db handles in use. testUserAdmin and adminUserAdmin are handles to
// the "test" and "admin" dbs respectively. Both testUserAdmin and adminUserAdmin are on the
// same connection (userAdminConn) which has been auth'd as a user with the
// 'userAdminAnyDatabase' role. Those will be used for manipulating the user defined roles
// used in the test. "testDB" is a handle to the test database on a connection that has been
// auth'd as 'testUser@test' - this is the connection that will be used to test how privilege
// enforcement works.
// test CRUD
hasAuthzError(testDB.foo.insert({a: 1}));
assert.throws(function() {
testDB.foo.findOne();
});
testUserAdmin.grantPrivilegesToRole(
'testRole1', [{resource: {db: 'test', collection: ''}, actions: ['find']}]);
hasAuthzError(testDB.foo.insert({a: 1}));
assert.doesNotThrow(function() {
testDB.foo.findOne();
});
assert.eq(0, testDB.foo.count());
assert.eq(0, testDB.foo.find().itcount());
testUserAdmin.grantPrivilegesToRole(
'testRole1', [{resource: {db: 'test', collection: 'foo'}, actions: ['insert']}]);
assert.writeOK(testDB.foo.insert({a: 1}));
assert.eq(1, testDB.foo.findOne().a);
assert.eq(1, testDB.foo.count());
assert.eq(1, testDB.foo.find().itcount());
hasAuthzError(testDB.foo.update({a: 1}, {$inc: {a: 1}}));
assert.eq(1, testDB.foo.findOne().a);
hasAuthzError(testDB.bar.insert({a: 1}));
assert.eq(0, testDB.bar.count());
adminUserAdmin.grantPrivilegesToRole(
'adminRole', [{resource: {db: '', collection: 'foo'}, actions: ['update']}]);
assert.writeOK(testDB.foo.update({a: 1}, {$inc: {a: 1}}));
assert.eq(2, testDB.foo.findOne().a);
assert.writeOK(testDB.foo.update({b: 1}, {$inc: {b: 1}}, true)); // upsert
assert.eq(2, testDB.foo.count());
assert.eq(2, testDB.foo.findOne({b: {$exists: true}}).b);
hasAuthzError(testDB.foo.remove({b: 2}));
assert.eq(2, testDB.foo.count());
adminUserAdmin.grantPrivilegesToRole(
'adminRole', [{resource: {db: '', collection: ''}, actions: ['remove']}]);
assert.writeOK(testDB.foo.remove({b: 2}));
assert.eq(1, testDB.foo.count());
// Test revoking privileges
testUserAdmin.revokePrivilegesFromRole(
'testRole1', [{resource: {db: 'test', collection: 'foo'}, actions: ['insert']}]);
hasAuthzError(testDB.foo.insert({a: 1}));
assert.eq(1, testDB.foo.count());
assert.writeOK(testDB.foo.update({a: 2}, {$inc: {a: 1}}));
assert.eq(3, testDB.foo.findOne({a: {$exists: true}}).a);
hasAuthzError(testDB.foo.update({c: 1}, {$inc: {c: 1}}, true)); // upsert should fail
assert.eq(1, testDB.foo.count());
// Test changeOwnPassword/changeOwnCustomData
assert.throws(function() {
testDB.changeUserPassword('testUser', 'password');
});
assert.throws(function() {
testDB.updateUser('testUser', {customData: {zipCode: 10036}});
});
assert.eq(null, testDB.getUser('testUser').customData);
testUserAdmin.grantPrivilegesToRole('testRole1',
[{
resource: {db: 'test', collection: ''},
actions: ['changeOwnPassword', 'changeOwnCustomData']
}]);
testDB.changeUserPassword('testUser', 'password');
assert(!testDB.auth('testUser', 'pwd'));
assert(testDB.auth('testUser', 'password'));
testDB.updateUser('testUser', {customData: {zipCode: 10036}});
assert.eq(10036, testDB.getUser('testUser').customData.zipCode);
testUserAdmin.revokeRolesFromRole('testRole2', ['testRole1']);
assert.throws(function() {
testDB.changeUserPassword('testUser', 'pwd');
});
assert.throws(function() {
testDB.foo.findOne();
});
assert.throws(function() {
testDB.updateUser('testUser', {customData: {zipCode: 10028}});
});
assert.eq(10036, testDB.getUser('testUser').customData.zipCode);
// Test changeAnyPassword/changeAnyCustomData
testUserAdmin.grantPrivilegesToRole('testRole2', [
{resource: {db: 'test', collection: ''}, actions: ['changePassword', 'changeCustomData']}
]);
testDB.changeUserPassword('testUser', 'pwd');
assert(!testDB.auth('testUser', 'password'));
assert(testDB.auth('testUser', 'pwd'));
testDB.updateUser('testUser', {customData: {zipCode: 10028}});
assert.eq(10028, testDB.getUser('testUser').customData.zipCode);
// Test privileges on the cluster resource
assert.commandFailed(testDB.runCommand({serverStatus: 1}));
adminUserAdmin.grantPrivilegesToRole('adminRole',
[{resource: {cluster: true}, actions: ['serverStatus']}]);
assert.commandWorked(testDB.serverStatus());
}
jsTest.log('Test standalone');
var conn = MongoRunner.runMongod({auth: ''});
runTest(conn);
MongoRunner.stopMongod(conn);
jsTest.log('Test sharding');
// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
var st = new ShardingTest(
{shards: 2, config: 3, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}});
runTest(st.s);
st.stop();
|