summaryrefslogtreecommitdiff
path: root/jstests/auth/user_defined_roles.js
blob: 0190ad9385e0967ea957be47b75cdc2d9d5ba6fc (plain)
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
/**
 * 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.hasWriteError());
        assert.eq(authzErrorCode, result.getWriteError().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.port);

jsTest.log('Test sharding');
var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1'});
runTest(st.s);
st.stop();