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
174
|
// Tests that $$USER_ROLES is able to be used in an "update" and "findAndModify" commands.
// @tags: [requires_fcv_70]
(function() {
"use strict";
const dbName = "test";
const collName = "coll";
function initialize(db) {
let engDoc = {
_id: 0,
allowedRoles: ["eng-app-prod", "eng-app-stg", "read"],
allowedRole: "read",
comment: "only for engineering team",
teamMembers: ["John", "Ashley", "Gina"],
yearlyEduBudget: 15000,
yearlyTnEBudget: 2000,
salesWins: 1000
};
let salesDoc = {
_id: 1,
allowedRoles: ["sales-person"],
allowedRole: "observe",
comment: "only for sales team",
salesWins: 1000
};
let testUpdate = {_id: 2, allowedRole: "test", teamMembersRights: ["testUpdate"]};
let testFindAndModify = {
_id: 3,
allowedRole: "write",
teamMembersRights: ["testFindAndModify"]
};
let coll = db.getCollection(collName);
assert.commandWorked(coll.insertMany([engDoc, salesDoc, testUpdate, testFindAndModify]));
}
// Test accessing $$USER_ROLES in the query portion of "update" command.
function runUpdateQuery(db) {
let coll = db.getCollection(collName);
let pre = coll.findOne(
{$expr: {$eq: [{$setIntersection: ["$allowedRoles", "$$USER_ROLES.role"]}, []]}});
var preSalesWins = pre.salesWins;
assert.commandWorked(coll.update(
{$expr: {$eq: [{$setIntersection: ["$allowedRoles", "$$USER_ROLES.role"]}, []]}},
{$inc: {salesWins: 1000}},
{multi: true}));
let post = coll.findOne(
{$expr: {$eq: [{$setIntersection: ["$allowedRoles", "$$USER_ROLES.role"]}, []]}});
var postSalesWins = post.salesWins;
assert.eq(postSalesWins, preSalesWins + 1000);
}
// Test accessing $$USER_ROLES in the update portion of "update" command.
function runUpdateUpdate(db) {
let coll = db.getCollection(collName);
assert.commandWorked(
coll.update({_id: 2}, [{$set: {"teamMembersRights": "$$USER_ROLES.role"}}]));
let post = coll.findOne({_id: 2});
let expectedResult = {
_id: 2,
allowedRole: "test",
teamMembersRights: ["readWriteAnyDatabase", "read"]
};
assert.eq(post, expectedResult);
}
// Test accessing $$USER_ROLES in the query portion of "findAndModify" command.
function runFindAndModifyQuery(db) {
let coll = db.getCollection(collName);
let pre = coll.findOne({$expr: {allowedRole: "$$USER_ROLES.role"}});
var preSalesWins = pre.salesWins;
db.coll.findAndModify({
query: {allowedRole: "read", $expr: {allowedRole: "$$USER_ROLES.role"}},
update: {$inc: {salesWins: 1000}}
});
let post = coll.findOne({$expr: {allowedRole: "$$USER_ROLES.role"}});
var postSalesWins = post.salesWins;
assert.eq(postSalesWins, preSalesWins + 1000);
}
// Test accessing $$USER_ROLES in the update portion of "findAndModify" command.
function runFindAndModifyUpdate(db) {
let coll = db.getCollection(collName);
coll.findAndModify({
query: {allowedRole: "write"},
update: [{$set: {"teamMembersRights": "$$USER_ROLES.role"}}]
});
let post = coll.findOne({_id: 3});
let expectedResult = {
_id: 3,
allowedRole: "write",
teamMembersRights: ["readWriteAnyDatabase", "read"]
};
assert.eq(post, expectedResult);
}
function runTest(conn, st = null) {
// Create a user on the admin database.
let admin = conn.getDB("admin");
assert.commandWorked(admin.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
admin.auth("admin", "admin");
if (st) {
// Shard the collection that will be used in the update and findAndModify commands.
assert.commandWorked(conn.getDB("admin").runCommand({enableSharding: dbName}));
st.shardColl(conn.getDB(dbName).getCollection(collName), {allowedRole: 1});
}
const db = conn.getDB(dbName);
let coll = db.getCollection(collName);
// Create a user that has roles on more than one database. The readWriteAnyDatabase is
// necessary for the inserts that follow to work.
assert.commandWorked(db.runCommand({
createUser: "user",
pwd: "pwd",
roles: [{role: "readWriteAnyDatabase", db: "admin"}, {role: "read", db: dbName}]
}));
// Logout of the admin user so that we can log into the other user so we can access those
// roles with $$USER_ROLES below.
admin.logout();
db.auth("user", "pwd");
initialize(db);
runUpdateQuery(db);
runUpdateUpdate(db);
runFindAndModifyQuery(db);
runFindAndModifyUpdate(db);
db.logout();
}
jsTest.log("Test standalone");
const mongod = MongoRunner.runMongod({auth: ""});
runTest(mongod);
MongoRunner.stopMongod(mongod);
jsTest.log("Test sharded cluster");
const st = new ShardingTest({
mongos: 1,
config: 1,
shards: 2,
keyFile: 'jstests/libs/key1',
});
runTest(st.s, st);
st.stop();
}());
|