mongo/jstests/auth/user_roles_find_agg.js
Zac 591928c619 SERVER-108478 JS formatted by prettier and remove clang-format (#39656)
GitOrigin-RevId: 6c8f6aded47f260aa4f7c231b17dae3302cb1e04
2025-08-21 17:27:09 +00:00

139 lines
5.1 KiB
JavaScript

// Tests that $$USER_ROLES works as expected in a find command and an aggregate command (on both a
// standalone mongod and a sharded cluster).
// @tags: [requires_fcv_70]
import {ShardingTest} from "jstests/libs/shardingtest.js";
const dbName = "test";
const findCollName = "find_coll";
const aggCollName = "team_budget";
function runFind(db) {
// We need to create a collection for the following findOne() to run upon and we need to insert
// a document in that collection so that the findOne() actually has a document to project the
// $$USER_ROLES onto.
let coll = db.getCollection(findCollName);
assert.commandWorked(coll.insert({a: 1}));
let result = coll.findOne({}, {myRoles: "$$USER_ROLES"});
assert.eq(
[
{_id: "admin.readWriteAnyDatabase", role: "readWriteAnyDatabase", db: "admin"},
{_id: "test.read", role: "read", db: dbName},
],
result.myRoles,
);
}
function runAgg(db) {
let engDoc = {
_id: 0,
allowedRoles: ["eng-app-prod", "eng-app-stg", "read"],
comment: "only for engineering team",
teamMembers: ["John", "Ashley", "Gina"],
yearlyEduBudget: 15000,
yearlyTnEBudget: 2000,
};
let salesDoc = {
_id: 1,
allowedRoles: ["sales-person"],
comment: "only for sales team",
salesWins: 1000,
};
let coll = db.getCollection(aggCollName);
assert.commandWorked(coll.insertMany([engDoc, salesDoc]));
// This will match the documents where the intersection between the allowedRoles field and the
// user's roles is not empty, i.e. the user's role allows them to see the document in the
// results. In this case, only the engDoc has the the "read" role that was assigned to the user,
// so only the engDoc will appear in the results.
let pipeline = [
{
$match: {$expr: {$not: {$eq: [{$setIntersection: ["$allowedRoles", "$$USER_ROLES.role"]}, []]}}},
},
];
let res = coll.aggregate(pipeline).toArray();
assert.eq([engDoc], res);
// Insert a document that has the currently authenticated user's roles in the allowedRoles
// field, and thus will match the following subpipeline.
let readDoc = {_id: 2, allowedRoles: ["readWriteAnyDatabase", "read"]};
assert.commandWorked(coll.insert(readDoc));
const subpipeline = [{$match: {$expr: {$eq: ["$allowedRoles", "$$USER_ROLES.role"]}}}];
// Ensure that $$USER_ROLES can be present in a $lookup subpipeline.
let findColl = db.getCollection(findCollName);
const lookupPipeline = [
{$lookup: {from: aggCollName, pipeline: subpipeline, as: "docThatMatchesRoles"}},
{$project: {_id: 0, docThatMatchesRoles: 1}},
];
const lookupRes = findColl.aggregate(lookupPipeline).toArray();
assert.eq([{"docThatMatchesRoles": [{"_id": 2, "allowedRoles": ["readWriteAnyDatabase", "read"]}]}], lookupRes);
// Ensure that $$USER_ROLES can be present in a $unionWith subpipeline. The result set should
// include the one document from findColl and the document from the unioned collection inserted
// above where the allowedRoles field has the currently authenticated user's roles.
const unionWithPipeline = [{$unionWith: {coll: aggCollName, pipeline: subpipeline}}, {$project: {_id: 0}}];
const unionWithRes = findColl.aggregate(unionWithPipeline).toArray();
assert.eq([{a: 1}, {allowedRoles: ["readWriteAnyDatabase", "read"]}], unionWithRes);
}
function runTest(conn, shardingTest = null) {
// Create a user on the admin database with the root role so that we can create users with other
// roles to other databases.
let admin = conn.getDB("admin");
assert.commandWorked(admin.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
admin.auth("admin", "admin");
if (shardingTest) {
// Shard the two collections that will be used in the find and aggregate commands.
assert.commandWorked(st.getDB("admin").runCommand({enableSharding: dbName}));
st.shardColl(st.getDB(dbName).getCollection(findCollName), {_id: 1});
st.shardColl(st.getDB(dbName).getCollection(aggCollName), {_id: 1});
}
const db = conn.getDB(dbName);
// 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");
runFind(db);
runAgg(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();