summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorBernard Gorman <bernard.gorman@gmail.com>2017-07-07 04:24:12 +0100
committerBernard Gorman <bernard.gorman@gmail.com>2017-07-07 14:38:33 +0100
commit286717ae5aa0c5a83ea8bf49b75158ae4af0b857 (patch)
tree8135a3c0506c0ac092e63cdfa887028f5d1c49e2 /jstests
parentd9e367b1ab30d9f4c61a845aac70af0aa607c26b (diff)
downloadmongo-286717ae5aa0c5a83ea8bf49b75158ae4af0b857.tar.gz
SERVER-19318 Add getMore authentication for collectionless aggregation namespaces
Diffstat (limited to 'jstests')
-rw-r--r--jstests/sharding/aggregation_currentop.js101
1 files changed, 79 insertions, 22 deletions
diff --git a/jstests/sharding/aggregation_currentop.js b/jstests/sharding/aggregation_currentop.js
index bdecea70c6b..f6ecbac58d5 100644
--- a/jstests/sharding/aggregation_currentop.js
+++ b/jstests/sharding/aggregation_currentop.js
@@ -58,8 +58,8 @@
privileges: [{resource: {cluster: true}, actions: ["inprog"]}]
}));
- assert.commandWorked(adminDB.runCommand(
- {createUser: "user_inprog", pwd: "pwd", roles: ["role_inprog", "readAnyDatabase"]}));
+ assert.commandWorked(
+ adminDB.runCommand({createUser: "user_inprog", pwd: "pwd", roles: ["role_inprog"]}));
assert.commandWorked(adminDB.runCommand(
{createUser: "user_no_inprog", pwd: "pwd", roles: ["readAnyDatabase"]}));
@@ -79,9 +79,9 @@
st.ensurePrimaryShard(clusterTestDB.getName(), shardRS.name);
// Run a command on the specified database and return a cursor over the result.
- function cmdCursor(inputDB, cmd) {
- return new DBCommandCursor(inputDB.getMongo(),
- assert.commandWorked(inputDB.runCommand(cmd)));
+ function cmdCursor(inputDB, cmd, batchSize) {
+ return new DBCommandCursor(
+ inputDB.getMongo(), assert.commandWorked(inputDB.runCommand(cmd)), batchSize);
}
// Restarts a replica set with additional parameters, and optionally re-authenticates.
@@ -152,8 +152,40 @@
awaitShell();
}
- // Runs a suite of tests for behaviour that is common to both the replica set and cluster
- // levels.
+ function getCollectionNameFromFullNamespace(ns) {
+ return ns.split(/\.(.+)/)[1];
+ }
+
+ // Generic function for running getMore on a $currentOp aggregation cursor and returning the
+ // command response.
+ function getMoreTest({conn, showAllUsers, getMoreBatchSize}) {
+ // Ensure that there are some other connections present so that the result set is larger
+ // than 1 $currentOp entry.
+ const otherConns = [new Mongo(conn.host), new Mongo(conn.host)];
+
+ // Log the other connections in as user_no_inprog so that they will show up for user_inprog
+ // with {allUsers: true} and user_no_inprog with {allUsers: false}.
+ for (let otherConn of otherConns) {
+ assert(otherConn.getDB("admin").auth("user_no_inprog", "pwd"));
+ }
+
+ const connAdminDB = conn.getDB("admin");
+
+ const aggCmdRes = assert.commandWorked(connAdminDB.runCommand({
+ aggregate: 1,
+ pipeline: [{$currentOp: {allUsers: showAllUsers, idleConnections: true}}],
+ cursor: {batchSize: 0}
+ }));
+ assert.neq(aggCmdRes.cursor.id, 0);
+
+ return connAdminDB.runCommand({
+ getMore: aggCmdRes.cursor.id,
+ collection: getCollectionNameFromFullNamespace(aggCmdRes.cursor.ns),
+ batchSize: (getMoreBatchSize || 100)
+ });
+ }
+
+ // Runs a suite of tests for behaviour common to both the replica set and cluster levels.
function runCommonTests(conn) {
const testDB = conn.getDB(jsTestName());
const adminDB = conn.getDB("admin");
@@ -182,12 +214,25 @@
{aggregate: 1, pipeline: [{$currentOp: {allUsers: true}}], cursor: {}}),
ErrorCodes.Unauthorized);
+ // Test that {aggregate: 1} fails when the first stage in the pipeline is not $currentOp.
+ assert.commandFailedWithCode(
+ adminDB.runCommand({aggregate: 1, pipeline: [{$match: {}}], cursor: {}}),
+ ErrorCodes.InvalidNamespace);
+
//
// Authenticate as user_inprog.
//
assert(adminDB.logout());
assert(adminDB.auth("user_inprog", "pwd"));
+ // Test that $currentOp fails when it is not the first stage in the pipeline. We use two
+ // $currentOp stages since any other stage in the initial position will trip the {aggregate:
+ // 1} namespace check.
+ assert.commandFailedWithCode(
+ adminDB.runCommand(
+ {aggregate: 1, pipeline: [{$currentOp: {}}, {$currentOp: {}}], cursor: {}}),
+ ErrorCodes.BadValue);
+
// Test that $currentOp fails when run as {aggregate: 1} on a database other than admin.
assert.commandFailedWithCode(
testDB.runCommand({aggregate: 1, pipeline: [{$currentOp: {}}], cursor: {}}),
@@ -206,19 +251,6 @@
adminDB.runCommand({aggregate: one, pipeline: [{$currentOp: {}}], cursor: {}}));
}
- // Test that {aggregate: 1} fails when the first stage in the pipeline is not $currentOp.
- assert.commandFailedWithCode(
- adminDB.runCommand({aggregate: 1, pipeline: [{$match: {}}], cursor: {}}),
- ErrorCodes.InvalidNamespace);
-
- // Test that $currentOp fails when it is not the first stage in the pipeline. We use two
- // $currentOp stages since any other stage in the initial position will trip the {aggregate:
- // 1} namespace check.
- assert.commandFailedWithCode(
- adminDB.runCommand(
- {aggregate: 1, pipeline: [{$currentOp: {}}, {$currentOp: {}}], cursor: {}}),
- ErrorCodes.BadValue);
-
// Test that $currentOp with {allUsers: true} succeeds for a user with the "inprog"
// privilege.
assert.commandWorked(adminDB.runCommand(
@@ -323,6 +355,24 @@
} else {
assert.eq(explainPlan.stages, expectedStages);
}
+
+ // Test that a user with the inprog privilege can run getMore on a $currentOp aggregation
+ // cursor which they created with {allUsers: true}.
+ let getMoreCmdRes = assert.commandWorked(
+ getMoreTest({conn: conn, showAllUsers: true, getMoreBatchSize: 1}));
+
+ // Test that a user without the inprog privilege cannot run getMore on a $currentOp
+ // aggregation cursor created by a user with {allUsers: true}.
+ assert(adminDB.logout());
+ assert(adminDB.auth("user_no_inprog", "pwd"));
+
+ assert.neq(getMoreCmdRes.cursor.id, 0);
+ assert.commandFailedWithCode(adminDB.runCommand({
+ getMore: getMoreCmdRes.cursor.id,
+ collection: getCollectionNameFromFullNamespace(getMoreCmdRes.cursor.ns),
+ batchSize: 100
+ }),
+ ErrorCodes.Unauthorized);
}
runCommonTests(shardConn);
@@ -380,7 +430,7 @@
5);
},
conn: shardConn,
- username: "user_no_inprog",
+ username: "admin",
password: "pwd"
});
@@ -411,7 +461,7 @@
5);
},
conn: shardConn,
- username: "user_inprog",
+ username: "admin",
password: "pwd"
});
@@ -437,6 +487,10 @@
waitForParallelShell(shardConn, awaitShell);
+ // Test that a user without the inprog privilege can run getMore on a $currentOp cursor which
+ // they created with {allUsers: false}.
+ assert.commandWorked(getMoreTest({conn: shardConn, showAllUsers: false}));
+
// Test that the allUsers parameter is ignored when authentication is disabled.
restartReplSet(shardRS, {shardsvr: null, keyFile: null});
@@ -463,6 +517,9 @@
assert.eq(aggAllUsersFalse, aggAllUsersTrue);
+ // Test that a user can run getMore on a $currentOp cursor when authentication is disabled.
+ assert.commandWorked(getMoreTest({conn: shardConn, showAllUsers: true}));
+
// Test that the host field is present and the shard field is absent when run on mongoD.
assert.eq(cmdCursor(shardAdminDB, {
aggregate: 1,