summaryrefslogtreecommitdiff
path: root/jstests/auth/getMore.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/auth/getMore.js')
-rw-r--r--jstests/auth/getMore.js682
1 files changed, 336 insertions, 346 deletions
diff --git a/jstests/auth/getMore.js b/jstests/auth/getMore.js
index d58c52a205c..4495d61200b 100644
--- a/jstests/auth/getMore.js
+++ b/jstests/auth/getMore.js
@@ -1,351 +1,341 @@
// Tests that a user can only run a getMore on a cursor that they created.
// @tags: [requires_sharding]
(function() {
- "use strict";
-
- // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session.
- TestData.disableImplicitSessions = true;
-
- function runTest(conn) {
- let adminDB = conn.getDB("admin");
- let isMaster = adminDB.runCommand("ismaster");
- assert.commandWorked(isMaster);
- const isMongos = (isMaster.msg === "isdbgrid");
-
- // Create the admin user.
- assert.commandWorked(
- adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
- assert.eq(1, adminDB.auth("admin", "admin"));
-
- // Set up the test database.
- const testDBName = "auth_getMore";
- let testDB = adminDB.getSiblingDB(testDBName);
- testDB.dropDatabase();
- assert.writeOK(testDB.foo.insert({_id: 0}));
- assert.writeOK(testDB.foo.insert({_id: 1}));
- assert.writeOK(testDB.foo.insert({_id: 2}));
-
- //
- // Test that a user can only run a getMore on a cursor that they created.
- //
-
- // Create two users, "Alice" and "Mallory".
- assert.commandWorked(
- testDB.runCommand({createUser: "Alice", pwd: "pwd", roles: ["readWrite"]}));
- assert.commandWorked(
- testDB.runCommand({createUser: "Mallory", pwd: "pwd", roles: ["readWrite"]}));
- adminDB.logout();
-
- // Test that "Mallory" cannot use a find cursor created by "Alice".
- assert.eq(1, testDB.auth("Alice", "pwd"));
- let res = assert.commandWorked(testDB.runCommand({find: "foo", batchSize: 0}));
- let cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
- assert.eq(1, testDB.auth("Mallory", "pwd"));
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from another user's find cursor");
- testDB.logout();
-
- // Test that "Mallory" cannot use a legacy find cursor created by "Alice".
- testDB.getMongo().forceReadMode("legacy");
- assert.eq(1, testDB.auth("Alice", "pwd"));
- let cursor = testDB.foo.find().batchSize(2);
+"use strict";
+
+// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session.
+TestData.disableImplicitSessions = true;
+
+function runTest(conn) {
+ let adminDB = conn.getDB("admin");
+ let isMaster = adminDB.runCommand("ismaster");
+ assert.commandWorked(isMaster);
+ const isMongos = (isMaster.msg === "isdbgrid");
+
+ // Create the admin user.
+ assert.commandWorked(adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
+ assert.eq(1, adminDB.auth("admin", "admin"));
+
+ // Set up the test database.
+ const testDBName = "auth_getMore";
+ let testDB = adminDB.getSiblingDB(testDBName);
+ testDB.dropDatabase();
+ assert.writeOK(testDB.foo.insert({_id: 0}));
+ assert.writeOK(testDB.foo.insert({_id: 1}));
+ assert.writeOK(testDB.foo.insert({_id: 2}));
+
+ //
+ // Test that a user can only run a getMore on a cursor that they created.
+ //
+
+ // Create two users, "Alice" and "Mallory".
+ assert.commandWorked(
+ testDB.runCommand({createUser: "Alice", pwd: "pwd", roles: ["readWrite"]}));
+ assert.commandWorked(
+ testDB.runCommand({createUser: "Mallory", pwd: "pwd", roles: ["readWrite"]}));
+ adminDB.logout();
+
+ // Test that "Mallory" cannot use a find cursor created by "Alice".
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ let res = assert.commandWorked(testDB.runCommand({find: "foo", batchSize: 0}));
+ let cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+ assert.eq(1, testDB.auth("Mallory", "pwd"));
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from another user's find cursor");
+ testDB.logout();
+
+ // Test that "Mallory" cannot use a legacy find cursor created by "Alice".
+ testDB.getMongo().forceReadMode("legacy");
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ let cursor = testDB.foo.find().batchSize(2);
+ cursor.next();
+ cursor.next();
+ testDB.logout();
+ assert.eq(1, testDB.auth("Mallory", "pwd"));
+ assert.throws(function() {
cursor.next();
- cursor.next();
- testDB.logout();
- assert.eq(1, testDB.auth("Mallory", "pwd"));
- assert.throws(function() {
- cursor.next();
- }, [], "read from another user's legacy find cursor");
- testDB.logout();
- testDB.getMongo().forceReadMode("commands");
-
- // Test that "Mallory" cannot use an aggregation cursor created by "Alice".
- assert.eq(1, testDB.auth("Alice", "pwd"));
- res = assert.commandWorked(
- testDB.runCommand({aggregate: "foo", pipeline: [], cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
- assert.eq(1, testDB.auth("Mallory", "pwd"));
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from another user's aggregate cursor");
- testDB.logout();
-
- // Test that "Mallory" cannot use a listCollections cursor created by "Alice".
- assert.eq(1, testDB.auth("Alice", "pwd"));
- res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
- assert.eq(1, testDB.auth("Mallory", "pwd"));
- assert.commandFailedWithCode(
- testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}),
- ErrorCodes.Unauthorized,
- "read from another user's listCollections cursor");
- testDB.logout();
-
- // Test that "Mallory" cannot use a listIndexes cursor created by "Alice".
- assert.eq(1, testDB.auth("Alice", "pwd"));
- res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
- assert.eq(1, testDB.auth("Mallory", "pwd"));
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from another user's listIndexes cursor");
- testDB.logout();
-
- //
- // Test that a user can call getMore on an indexStats cursor they created, unless the
- // indexStats privilege has been revoked in the meantime.
- //
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- assert.commandWorked(testDB.runCommand({
- createRole: "indexStatsOnly",
- privileges: [{resource: {db: testDBName, collection: "foo"}, actions: ["indexStats"]}],
- roles: []
- }));
- assert.commandWorked(
- testDB.runCommand({createUser: "Bob", pwd: "pwd", roles: ["indexStatsOnly"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Bob", "pwd"));
- res = assert.commandWorked(testDB.runCommand(
- {aggregate: "foo", pipeline: [{$indexStats: {}}], cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
-
- res = assert.commandWorked(testDB.runCommand(
- {aggregate: "foo", pipeline: [{$indexStats: {}}], cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- assert.commandWorked(
- testDB.runCommand({revokeRolesFromUser: "Bob", roles: ["indexStatsOnly"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Bob", "pwd"));
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from a cursor without required privileges");
- testDB.logout();
-
- //
- // Test that a user can call getMore on a listCollections cursor they created, unless the
- // readWrite privilege has been revoked in the meantime.
- //
-
- assert.eq(1, adminDB.auth("admin", "admin"));
-
- assert.commandWorked(
- testDB.runCommand({createUser: "Tom", pwd: "pwd", roles: ["readWrite"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Tom", "pwd"));
- res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- assert.commandWorked(
- testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}));
-
- res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- assert.commandWorked(testDB.runCommand({revokeRolesFromUser: "Tom", roles: ["readWrite"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Tom", "pwd"));
- assert.commandFailedWithCode(
- testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}),
- ErrorCodes.Unauthorized,
- "read from a cursor without required privileges");
- testDB.logout();
- //
- // Test that a user can call getMore on a listIndexes cursor they created, unless the
- // readWrite privilege has been revoked in the meantime.
- //
-
- assert.eq(1, adminDB.auth("admin", "admin"));
-
- assert.commandWorked(
- testDB.runCommand({createUser: "Bill", pwd: "pwd", roles: ["readWrite"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Bill", "pwd"));
- res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
-
- res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- assert.commandWorked(
- testDB.runCommand({revokeRolesFromUser: "Bill", roles: ["readWrite"]}));
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Bill", "pwd"));
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from a cursor without required privileges");
- testDB.logout();
-
- //
- // Test that a user can run a getMore on an aggregate cursor they created, unless some
- // privileges required for the pipeline have been revoked in the meantime.
- //
-
- assert.eq(1, testDB.auth("Alice", "pwd"));
- res = assert.commandWorked(testDB.runCommand({
- aggregate: "foo",
- pipeline: [{$match: {_id: 0}}, {$out: "out"}],
- cursor: {batchSize: 0}
- }));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
-
- res = assert.commandWorked(testDB.runCommand({
- aggregate: "foo",
- pipeline: [{$match: {_id: 0}}, {$out: "out"}],
- cursor: {batchSize: 0}
- }));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- testDB.logout();
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- testDB.revokeRolesFromUser("Alice", ["readWrite"]);
- testDB.grantRolesToUser("Alice", ["read"]);
- adminDB.logout();
-
- assert.eq(1, testDB.auth("Alice", "pwd"));
- assert.commandFailedWithCode(
- testDB.runCommand(
- {aggregate: "foo", pipeline: [{$match: {_id: 0}}, {$out: "out"}], cursor: {}}),
- ErrorCodes.Unauthorized,
- "user should no longer have write privileges");
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "wrote from a cursor without required privileges");
- testDB.logout();
-
- //
- // Test that if there were multiple users authenticated when the cursor was created, then at
- // least one of them must be authenticated in order to run getMore on the cursor.
- //
-
- assert.eq(1, adminDB.auth("admin", "admin"));
- assert.writeOK(testDB.bar.insert({_id: 0}));
-
- // Create a user "fooUser" on the test database that can read the "foo" collection.
- assert.commandWorked(testDB.runCommand({
- createRole: "readFoo",
- privileges: [{resource: {db: testDBName, collection: "foo"}, actions: ["find"]}],
- roles: []
- }));
- assert.commandWorked(
- testDB.runCommand({createUser: "fooUser", pwd: "pwd", roles: ["readFoo"]}));
-
- // Create a user "fooBarUser" on the admin database that can read the "foo" and "bar"
- // collections.
- assert.commandWorked(adminDB.runCommand({
- createRole: "readFooBar",
- privileges: [
- {resource: {db: testDBName, collection: "foo"}, actions: ["find"]},
- {resource: {db: testDBName, collection: "bar"}, actions: ["find"]}
- ],
- roles: []
- }));
- assert.commandWorked(
- adminDB.runCommand({createUser: "fooBarUser", pwd: "pwd", roles: ["readFooBar"]}));
-
- adminDB.logout();
-
- // Test that a cursor created by "fooUser" and "fooBarUser" can be used by "fooUser".
- assert.eq(1, testDB.auth("fooUser", "pwd"));
- assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
- res = assert.commandWorked(testDB.runCommand({find: "foo", batchSize: 0}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- adminDB.logout();
- assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
- testDB.logout();
-
- // Test that a cursor created by "fooUser" and "fooBarUser" cannot be used by "fooUser" if
- // "fooUser" does not have the privilege to read the collection.
- assert.eq(1, testDB.auth("fooUser", "pwd"));
- assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
- res = assert.commandWorked(testDB.runCommand({find: "bar", batchSize: 0}));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- adminDB.logout();
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "bar"}),
- ErrorCodes.Unauthorized,
- "read from a cursor without required privileges");
- testDB.logout();
-
- // Test that an aggregate cursor created by "fooUser" and "fooBarUser" cannot be used by
- // "fooUser" if "fooUser" does not have all privileges required by the pipeline.
- assert.eq(1, testDB.auth("fooUser", "pwd"));
- assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
- res = assert.commandWorked(testDB.runCommand({
- aggregate: "foo",
- pipeline: [
- {$match: {_id: 0}},
- {$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "bar"}}
- ],
- cursor: {batchSize: 0}
- }));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
-
- res = assert.commandWorked(testDB.runCommand({
- aggregate: "foo",
- pipeline: [
- {$match: {_id: 0}},
- {$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "bar"}}
- ],
- cursor: {batchSize: 0}
- }));
- cursorId = res.cursor.id;
- assert.neq(0, cursorId);
- adminDB.logout();
- assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
- ErrorCodes.Unauthorized,
- "read from a cursor without required privileges");
- testDB.logout();
- }
-
- // Run the test on a standalone.
- let conn = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"});
- runTest(conn);
- MongoRunner.stopMongod(conn);
-
- // Run the test on a sharded cluster.
- // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
- let cluster = new ShardingTest({
- shards: 1,
- mongos: 1,
- keyFile: "jstests/libs/key1",
- other: {shardOptions: {auth: ""}, shardAsReplicaSet: false}
- });
- runTest(cluster);
- cluster.stop();
+ }, [], "read from another user's legacy find cursor");
+ testDB.logout();
+ testDB.getMongo().forceReadMode("commands");
+
+ // Test that "Mallory" cannot use an aggregation cursor created by "Alice".
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ res = assert.commandWorked(
+ testDB.runCommand({aggregate: "foo", pipeline: [], cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+ assert.eq(1, testDB.auth("Mallory", "pwd"));
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from another user's aggregate cursor");
+ testDB.logout();
+
+ // Test that "Mallory" cannot use a listCollections cursor created by "Alice".
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+ assert.eq(1, testDB.auth("Mallory", "pwd"));
+ assert.commandFailedWithCode(
+ testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}),
+ ErrorCodes.Unauthorized,
+ "read from another user's listCollections cursor");
+ testDB.logout();
+
+ // Test that "Mallory" cannot use a listIndexes cursor created by "Alice".
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+ assert.eq(1, testDB.auth("Mallory", "pwd"));
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from another user's listIndexes cursor");
+ testDB.logout();
+
+ //
+ // Test that a user can call getMore on an indexStats cursor they created, unless the
+ // indexStats privilege has been revoked in the meantime.
+ //
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ assert.commandWorked(testDB.runCommand({
+ createRole: "indexStatsOnly",
+ privileges: [{resource: {db: testDBName, collection: "foo"}, actions: ["indexStats"]}],
+ roles: []
+ }));
+ assert.commandWorked(
+ testDB.runCommand({createUser: "Bob", pwd: "pwd", roles: ["indexStatsOnly"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Bob", "pwd"));
+ res = assert.commandWorked(testDB.runCommand(
+ {aggregate: "foo", pipeline: [{$indexStats: {}}], cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
+
+ res = assert.commandWorked(testDB.runCommand(
+ {aggregate: "foo", pipeline: [{$indexStats: {}}], cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ assert.commandWorked(
+ testDB.runCommand({revokeRolesFromUser: "Bob", roles: ["indexStatsOnly"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Bob", "pwd"));
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from a cursor without required privileges");
+ testDB.logout();
+
+ //
+ // Test that a user can call getMore on a listCollections cursor they created, unless the
+ // readWrite privilege has been revoked in the meantime.
+ //
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+
+ assert.commandWorked(testDB.runCommand({createUser: "Tom", pwd: "pwd", roles: ["readWrite"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Tom", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ assert.commandWorked(
+ testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}));
+
+ res = assert.commandWorked(testDB.runCommand({listCollections: 1, cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ assert.commandWorked(testDB.runCommand({revokeRolesFromUser: "Tom", roles: ["readWrite"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Tom", "pwd"));
+ assert.commandFailedWithCode(
+ testDB.runCommand({getMore: cursorId, collection: "$cmd.listCollections"}),
+ ErrorCodes.Unauthorized,
+ "read from a cursor without required privileges");
+ testDB.logout();
+ //
+ // Test that a user can call getMore on a listIndexes cursor they created, unless the
+ // readWrite privilege has been revoked in the meantime.
+ //
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+
+ assert.commandWorked(testDB.runCommand({createUser: "Bill", pwd: "pwd", roles: ["readWrite"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Bill", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
+
+ res = assert.commandWorked(testDB.runCommand({listIndexes: "foo", cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ assert.commandWorked(testDB.runCommand({revokeRolesFromUser: "Bill", roles: ["readWrite"]}));
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Bill", "pwd"));
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from a cursor without required privileges");
+ testDB.logout();
+
+ //
+ // Test that a user can run a getMore on an aggregate cursor they created, unless some
+ // privileges required for the pipeline have been revoked in the meantime.
+ //
+
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ res = assert.commandWorked(testDB.runCommand(
+ {aggregate: "foo", pipeline: [{$match: {_id: 0}}, {$out: "out"}], cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
+
+ res = assert.commandWorked(testDB.runCommand(
+ {aggregate: "foo", pipeline: [{$match: {_id: 0}}, {$out: "out"}], cursor: {batchSize: 0}}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ testDB.logout();
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ testDB.revokeRolesFromUser("Alice", ["readWrite"]);
+ testDB.grantRolesToUser("Alice", ["read"]);
+ adminDB.logout();
+
+ assert.eq(1, testDB.auth("Alice", "pwd"));
+ assert.commandFailedWithCode(
+ testDB.runCommand(
+ {aggregate: "foo", pipeline: [{$match: {_id: 0}}, {$out: "out"}], cursor: {}}),
+ ErrorCodes.Unauthorized,
+ "user should no longer have write privileges");
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "wrote from a cursor without required privileges");
+ testDB.logout();
+
+ //
+ // Test that if there were multiple users authenticated when the cursor was created, then at
+ // least one of them must be authenticated in order to run getMore on the cursor.
+ //
+
+ assert.eq(1, adminDB.auth("admin", "admin"));
+ assert.writeOK(testDB.bar.insert({_id: 0}));
+
+ // Create a user "fooUser" on the test database that can read the "foo" collection.
+ assert.commandWorked(testDB.runCommand({
+ createRole: "readFoo",
+ privileges: [{resource: {db: testDBName, collection: "foo"}, actions: ["find"]}],
+ roles: []
+ }));
+ assert.commandWorked(
+ testDB.runCommand({createUser: "fooUser", pwd: "pwd", roles: ["readFoo"]}));
+
+ // Create a user "fooBarUser" on the admin database that can read the "foo" and "bar"
+ // collections.
+ assert.commandWorked(adminDB.runCommand({
+ createRole: "readFooBar",
+ privileges: [
+ {resource: {db: testDBName, collection: "foo"}, actions: ["find"]},
+ {resource: {db: testDBName, collection: "bar"}, actions: ["find"]}
+ ],
+ roles: []
+ }));
+ assert.commandWorked(
+ adminDB.runCommand({createUser: "fooBarUser", pwd: "pwd", roles: ["readFooBar"]}));
+
+ adminDB.logout();
+
+ // Test that a cursor created by "fooUser" and "fooBarUser" can be used by "fooUser".
+ assert.eq(1, testDB.auth("fooUser", "pwd"));
+ assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({find: "foo", batchSize: 0}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ adminDB.logout();
+ assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
+ testDB.logout();
+
+ // Test that a cursor created by "fooUser" and "fooBarUser" cannot be used by "fooUser" if
+ // "fooUser" does not have the privilege to read the collection.
+ assert.eq(1, testDB.auth("fooUser", "pwd"));
+ assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({find: "bar", batchSize: 0}));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ adminDB.logout();
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "bar"}),
+ ErrorCodes.Unauthorized,
+ "read from a cursor without required privileges");
+ testDB.logout();
+
+ // Test that an aggregate cursor created by "fooUser" and "fooBarUser" cannot be used by
+ // "fooUser" if "fooUser" does not have all privileges required by the pipeline.
+ assert.eq(1, testDB.auth("fooUser", "pwd"));
+ assert.eq(1, adminDB.auth("fooBarUser", "pwd"));
+ res = assert.commandWorked(testDB.runCommand({
+ aggregate: "foo",
+ pipeline: [
+ {$match: {_id: 0}},
+ {$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "bar"}}
+ ],
+ cursor: {batchSize: 0}
+ }));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ assert.commandWorked(testDB.runCommand({getMore: cursorId, collection: "foo"}));
+
+ res = assert.commandWorked(testDB.runCommand({
+ aggregate: "foo",
+ pipeline: [
+ {$match: {_id: 0}},
+ {$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "bar"}}
+ ],
+ cursor: {batchSize: 0}
+ }));
+ cursorId = res.cursor.id;
+ assert.neq(0, cursorId);
+ adminDB.logout();
+ assert.commandFailedWithCode(testDB.runCommand({getMore: cursorId, collection: "foo"}),
+ ErrorCodes.Unauthorized,
+ "read from a cursor without required privileges");
+ testDB.logout();
+}
+
+// Run the test on a standalone.
+let conn = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"});
+runTest(conn);
+MongoRunner.stopMongod(conn);
+
+// Run the test on a sharded cluster.
+// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed.
+let cluster = new ShardingTest({
+ shards: 1,
+ mongos: 1,
+ keyFile: "jstests/libs/key1",
+ other: {shardOptions: {auth: ""}, shardAsReplicaSet: false}
+});
+runTest(cluster);
+cluster.stop();
}());