168 lines
6.7 KiB
JavaScript
168 lines
6.7 KiB
JavaScript
/**
|
|
* Tests that a user's ability to view open cursors via $currentOp obeys authentication rules on
|
|
* both mongoD and mongoS.
|
|
* @tags: [assumes_read_concern_unchanged, requires_auth, requires_journaling, requires_replication]
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
load("jstests/libs/fixture_helpers.js"); // For isMongos.
|
|
|
|
// TODO SERVER-32672: remove the 'skipGossipingClusterTime' flag.
|
|
TestData.skipGossipingClusterTime = true;
|
|
|
|
// Create a new sharded cluster for testing and enable auth.
|
|
const key = "jstests/libs/key1";
|
|
const st = new ShardingTest({name: jsTestName(), keyFile: key, shards: 1});
|
|
|
|
const shardConn = st.rs0.getPrimary();
|
|
const mongosConn = st.s;
|
|
|
|
shardConn.waitForClusterTime(60);
|
|
|
|
Random.setRandomSeed();
|
|
const pass = "a" + Random.rand();
|
|
|
|
// Create one root user and one regular user on the given connection.
|
|
function createUsers(conn) {
|
|
const adminDB = conn.getDB("admin");
|
|
adminDB.createUser({user: "ted", pwd: pass, roles: ["root"]});
|
|
assert(adminDB.auth("ted", pass), "Authentication 1 Failed");
|
|
adminDB.createUser({user: "yuta", pwd: pass, roles: ["readWriteAnyDatabase"]});
|
|
}
|
|
|
|
// Create the necessary users at both cluster and shard-local level.
|
|
createUsers(shardConn);
|
|
createUsers(mongosConn);
|
|
|
|
// Run the various auth tests on the given shard or mongoS connection.
|
|
function runCursorTests(conn) {
|
|
const db = conn.getDB("test");
|
|
const adminDB = db.getSiblingDB("admin");
|
|
|
|
// Log in as the root user.
|
|
assert.commandWorked(adminDB.logout());
|
|
assert(adminDB.auth("ted", pass), "Authentication 2 Failed");
|
|
|
|
const coll = db.jstests_currentop_cursors_auth;
|
|
coll.drop();
|
|
for (let i = 0; i < 5; ++i) {
|
|
assert.commandWorked(coll.insert({val: i}));
|
|
}
|
|
|
|
// Verify that we can see our own cursor with {allUsers: false}.
|
|
const cursorId = assert
|
|
.commandWorked(db.runCommand(
|
|
{find: "jstests_currentop_cursors_auth", batchSize: 2}))
|
|
.cursor.id;
|
|
|
|
let result =
|
|
adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, allUsers: false, idleCursors: true}},
|
|
{$match: {$and: [{type: "idleCursor"}, {"cursor.cursorId": cursorId}]}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 1, result);
|
|
|
|
// Log in as the non-root user.
|
|
assert.commandWorked(adminDB.logout());
|
|
assert(adminDB.auth("yuta", pass), "Authentication 3 Failed");
|
|
|
|
// Verify that we cannot see the root user's cursor.
|
|
result = adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, allUsers: false, idleCursors: true}},
|
|
{$match: {$and: [{type: "idleCursor"}, {"cursor.cursorId": cursorId}]}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 0, result);
|
|
|
|
// Make sure that the behavior is the same when 'allUsers' is not explicitly specified.
|
|
result = adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, idleCursors: true}},
|
|
{$match: {$and: [{type: "idleCursor"}, {"cursor.cursorId": cursorId}]}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 0, result);
|
|
|
|
// Verify that the user without the 'inprog' privilege cannot view shard cursors via mongoS.
|
|
if (FixtureHelpers.isMongos(db)) {
|
|
assert.commandFailedWithCode(adminDB.runCommand({
|
|
aggregate: 1,
|
|
pipeline: [{$currentOp: {localOps: false, idleCursors: true}}],
|
|
cursor: {}
|
|
}),
|
|
ErrorCodes.Unauthorized);
|
|
}
|
|
|
|
// Create a cursor with the second (non-root) user and confirm that we can see it.
|
|
const secondCursorId = assert
|
|
.commandWorked(db.runCommand(
|
|
{find: "jstests_currentop_cursors_auth", batchSize: 2}))
|
|
.cursor.id;
|
|
|
|
result =
|
|
adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, allUsers: false, idleCursors: true}},
|
|
{$match: {$and: [{type: "idleCursor"}, {"cursor.cursorId": secondCursorId}]}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 1, result);
|
|
|
|
// Log back in with the root user and confirm that the first cursor is still present.
|
|
assert.commandWorked(adminDB.logout());
|
|
assert(adminDB.auth("ted", pass), "Authentication 4 Failed");
|
|
|
|
result = adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, allUsers: false, idleCursors: true}},
|
|
{$match: {$and: [{type: "idleCursor"}, {"cursor.cursorId": cursorId}]}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 1, result);
|
|
|
|
// Confirm that the root user can see both users' cursors with {allUsers: true}.
|
|
result = adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: true, allUsers: true, idleCursors: true}},
|
|
{
|
|
$match: {
|
|
type: "idleCursor",
|
|
"cursor.cursorId": {$in: [cursorId, secondCursorId]}
|
|
}
|
|
}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 2, result);
|
|
|
|
// The root user can also see both cursors on the shard via mongoS with {localOps: false}.
|
|
if (FixtureHelpers.isMongos(db)) {
|
|
result = adminDB
|
|
.aggregate([
|
|
{$currentOp: {localOps: false, allUsers: true, idleCursors: true}},
|
|
{$match: {type: "idleCursor", shard: st.rs0.name}}
|
|
])
|
|
.toArray();
|
|
assert.eq(result.length, 2, result);
|
|
}
|
|
|
|
// Clean up the cursors so that they don't affect subsequent tests.
|
|
assert.commandWorked(
|
|
db.runCommand({killCursors: coll.getName(), cursors: [cursorId, secondCursorId]}));
|
|
|
|
// Make sure to logout to allow __system user to use the implicit session.
|
|
assert.commandWorked(adminDB.logout());
|
|
}
|
|
|
|
jsTestLog("Running cursor tests on mongoD");
|
|
runCursorTests(shardConn);
|
|
|
|
jsTestLog("Running cursor tests on mongoS");
|
|
runCursorTests(mongosConn);
|
|
|
|
st.stop();
|
|
})();
|