diff options
Diffstat (limited to 'jstests/auth')
67 files changed, 4388 insertions, 4519 deletions
diff --git a/jstests/auth/auth3.js b/jstests/auth/auth3.js index 6ded435c508..29f61f1c7ee 100644 --- a/jstests/auth/auth3.js +++ b/jstests/auth/auth3.js @@ -1,33 +1,33 @@ (function() { - 'use strict'; +'use strict'; - var conn = MongoRunner.runMongod({auth: ""}); +var conn = MongoRunner.runMongod({auth: ""}); - var admin = conn.getDB("admin"); - var errorCodeUnauthorized = 13; +var admin = conn.getDB("admin"); +var errorCodeUnauthorized = 13; - admin.createUser({user: "foo", pwd: "bar", roles: jsTest.adminUserRoles}); +admin.createUser({user: "foo", pwd: "bar", roles: jsTest.adminUserRoles}); - print("make sure curop, killop, and unlock fail"); +print("make sure curop, killop, and unlock fail"); - var x = admin.currentOp(); - assert(!("inprog" in x), tojson(x)); - assert.eq(x.code, errorCodeUnauthorized, tojson(x)); +var x = admin.currentOp(); +assert(!("inprog" in x), tojson(x)); +assert.eq(x.code, errorCodeUnauthorized, tojson(x)); - x = admin.killOp(123); - assert(!("info" in x), tojson(x)); - assert.eq(x.code, errorCodeUnauthorized, tojson(x)); +x = admin.killOp(123); +assert(!("info" in x), tojson(x)); +assert.eq(x.code, errorCodeUnauthorized, tojson(x)); - x = admin.fsyncUnlock(); - assert(x.errmsg != "fsyncUnlock called when not locked", tojson(x)); - assert.eq(x.code, errorCodeUnauthorized, tojson(x)); +x = admin.fsyncUnlock(); +assert(x.errmsg != "fsyncUnlock called when not locked", tojson(x)); +assert.eq(x.code, errorCodeUnauthorized, tojson(x)); - conn.getDB("admin").auth("foo", "bar"); +conn.getDB("admin").auth("foo", "bar"); - assert("inprog" in admin.currentOp()); - assert("info" in admin.killOp(123)); - assert.eq(admin.fsyncUnlock().errmsg, "fsyncUnlock called when not locked"); +assert("inprog" in admin.currentOp()); +assert("info" in admin.killOp(123)); +assert.eq(admin.fsyncUnlock().errmsg, "fsyncUnlock called when not locked"); - MongoRunner.stopMongod(conn, null, {user: "foo", pwd: "bar"}); +MongoRunner.stopMongod(conn, null, {user: "foo", pwd: "bar"}); })(); diff --git a/jstests/auth/auth_helpers.js b/jstests/auth/auth_helpers.js index 0e944560e0b..f2d9f458eac 100644 --- a/jstests/auth/auth_helpers.js +++ b/jstests/auth/auth_helpers.js @@ -1,24 +1,24 @@ // Test the db.auth() shell helper. (function() { - 'use strict'; +'use strict'; - const conn = MongoRunner.runMongod(); - const admin = conn.getDB('admin'); +const conn = MongoRunner.runMongod(); +const admin = conn.getDB('admin'); - admin.createUser({user: 'andy', pwd: 'a', roles: jsTest.adminUserRoles}); - assert(admin.auth({user: 'andy', pwd: 'a'})); - assert(admin.logout()); +admin.createUser({user: 'andy', pwd: 'a', roles: jsTest.adminUserRoles}); +assert(admin.auth({user: 'andy', pwd: 'a'})); +assert(admin.logout()); - // Try all the ways to call db.auth that uses SCRAM-SHA-1 or MONGODB-CR. - assert(admin.auth('andy', 'a')); - assert(admin.logout()); - assert(admin.auth({user: 'andy', pwd: 'a'})); - assert(admin.logout()); - assert(admin.auth({mechanism: 'SCRAM-SHA-1', user: 'andy', pwd: 'a'})); - assert(admin.logout()); +// Try all the ways to call db.auth that uses SCRAM-SHA-1 or MONGODB-CR. +assert(admin.auth('andy', 'a')); +assert(admin.logout()); +assert(admin.auth({user: 'andy', pwd: 'a'})); +assert(admin.logout()); +assert(admin.auth({mechanism: 'SCRAM-SHA-1', user: 'andy', pwd: 'a'})); +assert(admin.logout()); - // Invalid mechanisms shouldn't lead to authentication, but also shouldn't crash. - assert(!admin.auth({mechanism: 'this-mechanism-is-fake', user: 'andy', pwd: 'a'})); - MongoRunner.stopMongod(conn); +// Invalid mechanisms shouldn't lead to authentication, but also shouldn't crash. +assert(!admin.auth({mechanism: 'this-mechanism-is-fake', user: 'andy', pwd: 'a'})); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/auth_mechanism_discovery.js b/jstests/auth/auth_mechanism_discovery.js index e3f7c5d0551..78b150ec1aa 100644 --- a/jstests/auth/auth_mechanism_discovery.js +++ b/jstests/auth/auth_mechanism_discovery.js @@ -1,58 +1,55 @@ // Tests that a client will auto-discover a user's supported SASL mechanisms during auth(). // @tags: [requires_sharding] (function() { - "use strict"; +"use strict"; - function runTest(conn) { - const admin = conn.getDB("admin"); - const test = conn.getDB("test"); +function runTest(conn) { + const admin = conn.getDB("admin"); + const test = conn.getDB("test"); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); - // Verify user mechanism discovery. - function checkUser(username, mechanism) { - var createUser = {createUser: username, pwd: 'pwd', roles: []}; - if (mechanism !== undefined) { - createUser.mechanisms = [mechanism]; - } else { - // Create both variants, expect to prefer 256. - mechanism = 'SCRAM-SHA-256'; - } - assert.commandWorked(test.runCommand(createUser)); - assert.eq(test._getDefaultAuthenticationMechanism(username, test.getName()), mechanism); - assert(test.auth(username, 'pwd')); - test.logout(); + // Verify user mechanism discovery. + function checkUser(username, mechanism) { + var createUser = {createUser: username, pwd: 'pwd', roles: []}; + if (mechanism !== undefined) { + createUser.mechanisms = [mechanism]; + } else { + // Create both variants, expect to prefer 256. + mechanism = 'SCRAM-SHA-256'; } - checkUser('userSha1', 'SCRAM-SHA-1'); - checkUser('userSha256', 'SCRAM-SHA-256'); - checkUser('userAll'); - - // Verify override of mechanism discovery. - // Depends on 'userAll' user created above. - assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), - 'SCRAM-SHA-256'); - test._defaultAuthenticationMechanism = 'SCRAM-SHA-1'; - assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), - 'SCRAM-SHA-1'); - test._defaultAuthenticationMechanism = 'NO-SUCH-MECHANISM'; - assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), - 'SCRAM-SHA-256'); + assert.commandWorked(test.runCommand(createUser)); + assert.eq(test._getDefaultAuthenticationMechanism(username, test.getName()), mechanism); + assert(test.auth(username, 'pwd')); + test.logout(); } + checkUser('userSha1', 'SCRAM-SHA-1'); + checkUser('userSha256', 'SCRAM-SHA-256'); + checkUser('userAll'); + + // Verify override of mechanism discovery. + // Depends on 'userAll' user created above. + assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), 'SCRAM-SHA-256'); + test._defaultAuthenticationMechanism = 'SCRAM-SHA-1'; + assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), 'SCRAM-SHA-1'); + test._defaultAuthenticationMechanism = 'NO-SUCH-MECHANISM'; + assert.eq(test._getDefaultAuthenticationMechanism('userAll', test.getName()), 'SCRAM-SHA-256'); +} - // Test standalone. - const m = MongoRunner.runMongod({auth: ""}); - runTest(m); - MongoRunner.stopMongod(m); +// Test standalone. +const m = MongoRunner.runMongod({auth: ""}); +runTest(m); +MongoRunner.stopMongod(m); - // Test sharded. - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runTest(st.s0); - st.stop(); +// Test sharded. +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/auth_mechanisms_parsing.js b/jstests/auth/auth_mechanisms_parsing.js index 72f906b3c68..3954963b885 100644 --- a/jstests/auth/auth_mechanisms_parsing.js +++ b/jstests/auth/auth_mechanisms_parsing.js @@ -1,13 +1,13 @@ // Test for stripping whitespace for authenticationMechanisms (function() { - "use strict"; +"use strict"; - const conn = MongoRunner.runMongod( - {setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256, PLAIN"}); +const conn = MongoRunner.runMongod( + {setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256, PLAIN"}); - const cmdOut = conn.getDB('admin').runCommand({getParameter: 1, authenticationMechanisms: 1}); +const cmdOut = conn.getDB('admin').runCommand({getParameter: 1, authenticationMechanisms: 1}); - // Check to see if whitespace in front of PLAIN is stripped - assert.sameMembers(cmdOut.authenticationMechanisms, ["SCRAM-SHA-1", "SCRAM-SHA-256", "PLAIN"]); - MongoRunner.stopMongod(conn); +// Check to see if whitespace in front of PLAIN is stripped +assert.sameMembers(cmdOut.authenticationMechanisms, ["SCRAM-SHA-1", "SCRAM-SHA-256", "PLAIN"]); +MongoRunner.stopMongod(conn); }()); diff --git a/jstests/auth/authentication_restrictions.js b/jstests/auth/authentication_restrictions.js index 1f08b3e6d6d..172db043770 100644 --- a/jstests/auth/authentication_restrictions.js +++ b/jstests/auth/authentication_restrictions.js @@ -4,224 +4,214 @@ */ (function() { - 'use strict'; - - // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. - TestData.disableImplicitSessions = true; - - function testConnection( - conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { - load("jstests/libs/host_ipaddr.js"); - - // Create a session which observes an eventually consistent view of user data - var eventualDb = eventuallyConsistentConn.getDB("admin"); - - // Create a session for modifying user data during the life of the test - var adminSession = new Mongo("localhost:" + conn.port); - var admin = adminSession.getDB("admin"); - assert.commandWorked(admin.runCommand( - {createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})); - assert(admin.auth("admin", "admin")); - - // Create a strongly consistent session for consuming user data - var db = conn.getDB("admin"); - - // Create a strongly consistent session for consuming user data, with a non-localhost - // source IP. - var externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); - var externalDb = externalMongo.getDB("admin"); - - assert.commandWorked(admin.runCommand({ - createUser: "user2", - pwd: "user", - roles: [], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert.commandWorked(admin.runCommand({createUser: "user3", pwd: "user", roles: []})); - assert.commandWorked(admin.runCommand( - {updateUser: "user3", authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}]})); - - print("=== User creation tests"); - print( - "When a client creates users with empty authenticationRestrictions, the operation succeeds, though it has no effect"); - assert.commandWorked(admin.runCommand( - {createUser: "user4", pwd: "user", roles: [], authenticationRestrictions: []})); - assert(!Object.keys(admin.system.users.findOne({user: "user4"})) - .includes("authenticationRestrictions")); - - print( - "When a client updates a user's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field"); - assert.commandWorked(admin.runCommand({createUser: "user5", pwd: "user", roles: []})); - assert.commandWorked( - admin.runCommand({updateUser: "user5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand( - {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - assert.commandWorked( - admin.runCommand({updateUser: "user5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - - print( - "When a client updates a user's authenticationRestrictions to be null or undefined, the operation fails"); - assert.commandWorked(admin.runCommand( - {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - assert.commandFailed( - admin.runCommand({updateUser: "user5", authenticationRestrictions: null})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - assert.commandFailed( - admin.runCommand({updateUser: "user5", authenticationRestrictions: undefined})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) - .includes("authenticationRestrictions")); - - print( - "When a client creates users, it may use clientSource and serverAddress authenticationRestrictions"); - assert.commandWorked(admin.runCommand({ - createUser: "user6", - pwd: "user", - roles: [], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert.commandWorked(admin.runCommand({ - createUser: "user7", - pwd: "user", - roles: [], - authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] - })); - assert.commandWorked(admin.runCommand({ - createUser: "user8", - pwd: "user", - roles: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] - })); - assert.commandWorked(admin.runCommand({ - createUser: "user9", - pwd: "user", - roles: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}] - })); - assert.commandFailed(admin.runCommand({ - createUser: "user10", - pwd: "user", - roles: [], - authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}] - })); - - print("=== Localhost access tests"); - - print( - "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\"}, it will succeed"); - assert(db.auth("user6", "user")); - - print( - "When a client on the loopback authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will succeed"); - assert(db.auth("user7", "user")); - - print( - "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will succeed"); - assert(db.auth("user8", "user")); - - print("=== Remote access tests"); - print( - "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user6", "user")); - - print( - "When a client on the external interface authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user7", "user")); - - print( - "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user8", "user")); - - print("=== Invalidation tests"); - print( - "When a client removes all authenticationRestrictions from a user, authentication will succeed"); - assert.commandWorked(admin.runCommand({ - createUser: "user11", - pwd: "user", - roles: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] - })); - assert(!externalDb.auth("user11", "user")); - assert.commandWorked( - admin.runCommand({updateUser: "user11", authenticationRestrictions: []})); - assert(externalDb.auth("user11", "user")); - - print( - "When a client sets authenticationRestrictions on a user, authorization privileges are revoked"); - assert.commandWorked(admin.runCommand( - {createUser: "user12", pwd: "user", roles: [{role: "readWrite", db: "test"}]})); - - assert(db.auth("user12", "user")); - assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - - sleepUntilUserDataPropagated(); - assert(eventualDb.auth("user12", "user")); - assert.commandWorked( - eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - - assert.commandWorked(admin.runCommand( - {updateUser: "user12", authenticationRestrictions: [{clientSource: ["192.0.2.0"]}]})); - - assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - - sleepUntilUserDataRefreshed(); - assert.commandFailed( - eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - } - - print("Testing standalone"); - var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); - testConnection(conn, conn, function() {}, function() {}); - MongoRunner.stopMongod(conn); - - var keyfile = "jstests/libs/key1"; - - print("Testing replicaset"); - var rst = new ReplSetTest( - {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); - var nodes = rst.startSet(); - rst.initiate(); - rst.awaitSecondaryNodes(); - var awaitReplication = function() { - authutil.asCluster(nodes, "jstests/libs/key1", function() { - rst.awaitReplication(); - }); - }; - - testConnection(rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication); - rst.stopSet(); - - print("Testing sharded cluster"); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest({ - mongos: 2, - config: 3, - shard: 1, - keyFile: keyfile, - other: { - mongosOptions: {bind_ip_all: "", auth: null}, - configOptions: {auth: null}, - shardOptions: {auth: null}, - shardAsReplicaSet: false - } +'use strict'; + +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + +function testConnection( + conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { + load("jstests/libs/host_ipaddr.js"); + + // Create a session which observes an eventually consistent view of user data + var eventualDb = eventuallyConsistentConn.getDB("admin"); + + // Create a session for modifying user data during the life of the test + var adminSession = new Mongo("localhost:" + conn.port); + var admin = adminSession.getDB("admin"); + assert.commandWorked(admin.runCommand( + {createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})); + assert(admin.auth("admin", "admin")); + + // Create a strongly consistent session for consuming user data + var db = conn.getDB("admin"); + + // Create a strongly consistent session for consuming user data, with a non-localhost + // source IP. + var externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); + var externalDb = externalMongo.getDB("admin"); + + assert.commandWorked(admin.runCommand({ + createUser: "user2", + pwd: "user", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({createUser: "user3", pwd: "user", roles: []})); + assert.commandWorked(admin.runCommand( + {updateUser: "user3", authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}]})); + + print("=== User creation tests"); + print( + "When a client creates users with empty authenticationRestrictions, the operation succeeds, though it has no effect"); + assert.commandWorked(admin.runCommand( + {createUser: "user4", pwd: "user", roles: [], authenticationRestrictions: []})); + assert(!Object.keys(admin.system.users.findOne({user: "user4"})) + .includes("authenticationRestrictions")); + + print( + "When a client updates a user's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field"); + assert.commandWorked(admin.runCommand({createUser: "user5", pwd: "user", roles: []})); + assert.commandWorked(admin.runCommand({updateUser: "user5", authenticationRestrictions: []})); + assert(!Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand( + {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); + assert(Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({updateUser: "user5", authenticationRestrictions: []})); + assert(!Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + + print( + "When a client updates a user's authenticationRestrictions to be null or undefined, the operation fails"); + assert.commandWorked(admin.runCommand( + {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); + assert(Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + assert.commandFailed(admin.runCommand({updateUser: "user5", authenticationRestrictions: null})); + assert(Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + assert.commandFailed( + admin.runCommand({updateUser: "user5", authenticationRestrictions: undefined})); + assert(Object.keys(admin.system.users.findOne({user: "user5"})) + .includes("authenticationRestrictions")); + + print( + "When a client creates users, it may use clientSource and serverAddress authenticationRestrictions"); + assert.commandWorked(admin.runCommand({ + createUser: "user6", + pwd: "user", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({ + createUser: "user7", + pwd: "user", + roles: [], + authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({ + createUser: "user8", + pwd: "user", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({ + createUser: "user9", + pwd: "user", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}] + })); + assert.commandFailed(admin.runCommand({ + createUser: "user10", + pwd: "user", + roles: [], + authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}] + })); + + print("=== Localhost access tests"); + + print( + "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\"}, it will succeed"); + assert(db.auth("user6", "user")); + + print( + "When a client on the loopback authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will succeed"); + assert(db.auth("user7", "user")); + + print( + "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will succeed"); + assert(db.auth("user8", "user")); + + print("=== Remote access tests"); + print( + "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user6", "user")); + + print( + "When a client on the external interface authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user7", "user")); + + print( + "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user8", "user")); + + print("=== Invalidation tests"); + print( + "When a client removes all authenticationRestrictions from a user, authentication will succeed"); + assert.commandWorked(admin.runCommand({ + createUser: "user11", + pwd: "user", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] + })); + assert(!externalDb.auth("user11", "user")); + assert.commandWorked(admin.runCommand({updateUser: "user11", authenticationRestrictions: []})); + assert(externalDb.auth("user11", "user")); + + print( + "When a client sets authenticationRestrictions on a user, authorization privileges are revoked"); + assert.commandWorked(admin.runCommand( + {createUser: "user12", pwd: "user", roles: [{role: "readWrite", db: "test"}]})); + + assert(db.auth("user12", "user")); + assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + + sleepUntilUserDataPropagated(); + assert(eventualDb.auth("user12", "user")); + assert.commandWorked(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + + assert.commandWorked(admin.runCommand( + {updateUser: "user12", authenticationRestrictions: [{clientSource: ["192.0.2.0"]}]})); + + assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + + sleepUntilUserDataRefreshed(); + assert.commandFailed(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); +} + +print("Testing standalone"); +var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); +testConnection(conn, conn, function() {}, function() {}); +MongoRunner.stopMongod(conn); + +var keyfile = "jstests/libs/key1"; + +print("Testing replicaset"); +var rst = new ReplSetTest( + {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); +var nodes = rst.startSet(); +rst.initiate(); +rst.awaitSecondaryNodes(); +var awaitReplication = function() { + authutil.asCluster(nodes, "jstests/libs/key1", function() { + rst.awaitReplication(); }); - testConnection(st.s0, - st.s1, - function() {}, - function() { - sleep(40 * 1000); // Wait for mongos user cache invalidation - }); - st.stop(); - +}; + +testConnection(rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication); +rst.stopSet(); + +print("Testing sharded cluster"); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest({ + mongos: 2, + config: 3, + shard: 1, + keyFile: keyfile, + other: { + mongosOptions: {bind_ip_all: "", auth: null}, + configOptions: {auth: null}, + shardOptions: {auth: null}, + shardAsReplicaSet: false + } +}); +testConnection(st.s0, + st.s1, + function() {}, + function() { + sleep(40 * 1000); // Wait for mongos user cache invalidation + }); +st.stop(); }()); diff --git a/jstests/auth/authentication_restrictions_role.js b/jstests/auth/authentication_restrictions_role.js index 3f23cfdcb92..70256fba7f5 100644 --- a/jstests/auth/authentication_restrictions_role.js +++ b/jstests/auth/authentication_restrictions_role.js @@ -4,424 +4,402 @@ */ (function() { - 'use strict'; - - // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. - TestData.disableImplicitSessions = true; - - function testRestrictionCreationAndEnforcement( - conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { - load("jstests/libs/host_ipaddr.js"); - - // Create a session which observes an eventually consistent view of user data - var eventualDb = eventuallyConsistentConn.getDB("admin"); - - // Create a session for modifying user data during the life of the test - var adminSession = new Mongo("127.0.0.1:" + conn.port); - var admin = adminSession.getDB("admin"); - assert.commandWorked(admin.runCommand( - {createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})); - assert(admin.auth("admin", "admin")); - - // Create a strongly consistent session for consuming user data - var db = conn.getDB("admin"); - - // Create a strongly consistent session for consuming user data, with a non-localhost - // source IP. - var externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); - var externalDb = externalMongo.getDB("admin"); - - assert.commandWorked(admin.runCommand({ - createRole: "role2", - roles: [], - privileges: [], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert(Object.keys(admin.system.roles.findOne({role: "role2"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({createRole: "role3", roles: [], privileges: []})); - - print("=== Role creation tests"); - print( - "When a client creates roles with empty authenticationRestrictions, the operation succeeds, though it has no effect"); - assert.commandWorked(admin.runCommand( - {createRole: "role4", roles: [], privileges: [], authenticationRestrictions: []})); - assert(!Object.keys(admin.system.roles.findOne({role: "role4"})) - .includes("authenticationRestrictions")); - - print( - "When a client updates a role's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field"); - assert.commandWorked(admin.runCommand({createRole: "role5", roles: [], privileges: []})); - assert.commandWorked( - admin.runCommand({updateRole: "role5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.roles.findOne({role: "role5"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand( - {updateRole: "role5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.roles.findOne({role: "role5"})) - .includes("authenticationRestrictions")); - assert.commandWorked( - admin.runCommand({updateRole: "role5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.roles.findOne({role: "role5"})) - .includes("authenticationRestrictions")); - - print( - "When a client creates roles, it may use clientSource and serverAddress authenticationRestrictions"); - assert.commandWorked(admin.runCommand({ - createRole: "role6", - roles: [], - privileges: [], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert(Object.keys(admin.system.roles.findOne({role: "role6"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ - createRole: "role7", - roles: [], - privileges: [], - authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] - })); - assert(Object.keys(admin.system.roles.findOne({role: "role7"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ - createRole: "role8", - roles: [], - privileges: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] - })); - assert(Object.keys(admin.system.roles.findOne({role: "role8"})) - .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ - createRole: "role9", - roles: [], - privileges: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}] - })); - assert(Object.keys(admin.system.roles.findOne({role: "role9"})) - .includes("authenticationRestrictions")); - assert.commandFailed(admin.runCommand({ - createRole: "role10", - roles: [], - privileges: [], - authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}] - })); - - print("=== Localhost access tests"); - print( - "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\"}, it will succeed"); - assert.commandWorked( - admin.runCommand({createUser: "user6", pwd: "user", roles: ["role6"]})); - assert(db.auth("user6", "user")); - - print( - "When a client on the loopback authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will succeed"); - assert.commandWorked( - admin.runCommand({createUser: "user7", pwd: "user", roles: ["role7"]})); - assert(db.auth("user7", "user")); - - print( - "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will succeed"); - assert.commandWorked( - admin.runCommand({createUser: "user8", pwd: "user", roles: ["role8"]})); - assert(db.auth("user8", "user")); - - print("=== Remote access tests"); - print( - "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user6", "user")); - - print( - "When a client on the external interface authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user7", "user")); - - print( - "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will fail"); - assert(!externalDb.auth("user8", "user")); - - print("=== Invalidation tests"); - print( - "When a client removes all authenticationRestrictions from a role, authentication will succeed"); - assert.commandWorked(admin.runCommand({ - createRole: "role11", - roles: [], - privileges: [], - authenticationRestrictions: - [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] - })); - assert.commandWorked( - admin.runCommand({createUser: "user11", pwd: "user", roles: ["role11"]})); - assert(!externalDb.auth("user11", "user")); - assert.commandWorked( - admin.runCommand({updateRole: "role11", authenticationRestrictions: []})); - assert(externalDb.auth("user11", "user")); - - print( - "When a client sets authenticationRestrictions on a role, authorization privileges are revoked"); - assert.commandWorked(admin.runCommand({ - createRole: "role12", - roles: [], - privileges: [{resource: {db: "test", collection: "foo"}, actions: ["find"]}], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert.commandWorked( - admin.runCommand({createUser: "user12", pwd: "user", roles: ["role12"]})); - assert(db.auth("user12", "user")); - assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - sleepUntilUserDataPropagated(); - assert(eventualDb.auth("user12", "user")); - assert.commandWorked( - eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - assert.commandWorked(admin.runCommand( - {updateRole: "role12", authenticationRestrictions: [{clientSource: ["192.168.2.0"]}]})); - assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - sleepUntilUserDataRefreshed(); - assert.commandFailed( - eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); +'use strict'; + +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + +function testRestrictionCreationAndEnforcement( + conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { + load("jstests/libs/host_ipaddr.js"); + + // Create a session which observes an eventually consistent view of user data + var eventualDb = eventuallyConsistentConn.getDB("admin"); + + // Create a session for modifying user data during the life of the test + var adminSession = new Mongo("127.0.0.1:" + conn.port); + var admin = adminSession.getDB("admin"); + assert.commandWorked(admin.runCommand( + {createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})); + assert(admin.auth("admin", "admin")); + + // Create a strongly consistent session for consuming user data + var db = conn.getDB("admin"); + + // Create a strongly consistent session for consuming user data, with a non-localhost + // source IP. + var externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); + var externalDb = externalMongo.getDB("admin"); + + assert.commandWorked(admin.runCommand({ + createRole: "role2", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert(Object.keys(admin.system.roles.findOne({role: "role2"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({createRole: "role3", roles: [], privileges: []})); + + print("=== Role creation tests"); + print( + "When a client creates roles with empty authenticationRestrictions, the operation succeeds, though it has no effect"); + assert.commandWorked(admin.runCommand( + {createRole: "role4", roles: [], privileges: [], authenticationRestrictions: []})); + assert(!Object.keys(admin.system.roles.findOne({role: "role4"})) + .includes("authenticationRestrictions")); + + print( + "When a client updates a role's authenticationRestrictions to be empty, the operation succeeds, and removes the authenticationRestrictions field"); + assert.commandWorked(admin.runCommand({createRole: "role5", roles: [], privileges: []})); + assert.commandWorked(admin.runCommand({updateRole: "role5", authenticationRestrictions: []})); + assert(!Object.keys(admin.system.roles.findOne({role: "role5"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand( + {updateRole: "role5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); + assert(Object.keys(admin.system.roles.findOne({role: "role5"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({updateRole: "role5", authenticationRestrictions: []})); + assert(!Object.keys(admin.system.roles.findOne({role: "role5"})) + .includes("authenticationRestrictions")); + + print( + "When a client creates roles, it may use clientSource and serverAddress authenticationRestrictions"); + assert.commandWorked(admin.runCommand({ + createRole: "role6", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert(Object.keys(admin.system.roles.findOne({role: "role6"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({ + createRole: "role7", + roles: [], + privileges: [], + authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] + })); + assert(Object.keys(admin.system.roles.findOne({role: "role7"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({ + createRole: "role8", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] + })); + assert(Object.keys(admin.system.roles.findOne({role: "role8"})) + .includes("authenticationRestrictions")); + assert.commandWorked(admin.runCommand({ + createRole: "role9", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}] + })); + assert(Object.keys(admin.system.roles.findOne({role: "role9"})) + .includes("authenticationRestrictions")); + assert.commandFailed(admin.runCommand({ + createRole: "role10", + roles: [], + privileges: [], + authenticationRestrictions: [{invalidRestriction: ["127.0.0.1"]}] + })); + + print("=== Localhost access tests"); + print( + "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\"}, it will succeed"); + assert.commandWorked(admin.runCommand({createUser: "user6", pwd: "user", roles: ["role6"]})); + assert(db.auth("user6", "user")); + + print( + "When a client on the loopback authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will succeed"); + assert.commandWorked(admin.runCommand({createUser: "user7", pwd: "user", roles: ["role7"]})); + assert(db.auth("user7", "user")); + + print( + "When a client on the loopback authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will succeed"); + assert.commandWorked(admin.runCommand({createUser: "user8", pwd: "user", roles: ["role8"]})); + assert(db.auth("user8", "user")); + + print("=== Remote access tests"); + print( + "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user6", "user")); + + print( + "When a client on the external interface authenticates to a user with {serverAddress: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user7", "user")); + + print( + "When a client on the external interface authenticates to a user with {clientSource: \"127.0.0.1\", serverAddress: \"127.0.0.1\"}, it will fail"); + assert(!externalDb.auth("user8", "user")); + + print("=== Invalidation tests"); + print( + "When a client removes all authenticationRestrictions from a role, authentication will succeed"); + assert.commandWorked(admin.runCommand({ + createRole: "role11", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({createUser: "user11", pwd: "user", roles: ["role11"]})); + assert(!externalDb.auth("user11", "user")); + assert.commandWorked(admin.runCommand({updateRole: "role11", authenticationRestrictions: []})); + assert(externalDb.auth("user11", "user")); + + print( + "When a client sets authenticationRestrictions on a role, authorization privileges are revoked"); + assert.commandWorked(admin.runCommand({ + createRole: "role12", + roles: [], + privileges: [{resource: {db: "test", collection: "foo"}, actions: ["find"]}], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({createUser: "user12", pwd: "user", roles: ["role12"]})); + assert(db.auth("user12", "user")); + assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + sleepUntilUserDataPropagated(); + assert(eventualDb.auth("user12", "user")); + assert.commandWorked(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + assert.commandWorked(admin.runCommand( + {updateRole: "role12", authenticationRestrictions: [{clientSource: ["192.168.2.0"]}]})); + assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + sleepUntilUserDataRefreshed(); + assert.commandFailed(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); +} + +function testUsersInfoCommand(conn) { + function forEachUser(res, assertFun) { + assert(res.hasOwnProperty("users")); + print("Users: " + tojson(res.users)); + assert.gt(res.users.length, 0); + res.users.forEach(assertFun); } - function testUsersInfoCommand(conn) { - function forEachUser(res, assertFun) { - assert(res.hasOwnProperty("users")); - print("Users: " + tojson(res.users)); - assert.gt(res.users.length, 0); - res.users.forEach(assertFun); - } - - var admin = conn.getDB("admin"); - assert(admin.auth("admin", "admin")); - - assert.commandWorked(admin.runCommand({createUser: "user", pwd: "pwd", roles: []})); - assert.commandWorked(admin.runCommand({ - createUser: "restrictedUser", - pwd: "pwd", - roles: [], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - assert.commandWorked(admin.runCommand({ - createRole: "restrictedRole", - roles: [], - privileges: [], - authenticationRestrictions: [{clientSource: ["127.0.0.2"]}] - })); - assert.commandWorked(admin.runCommand( - {createUser: "userWithRestrictedRole", pwd: "pwd", roles: ["restrictedRole"]})); - assert.commandWorked(admin.runCommand({ - createUser: "restrictedUserWithRestrictedRole", - pwd: "pwd", - roles: ["restrictedRole"], - authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] - })); - - print( - "Calling usersInfo for all users on a database with showAuthenticationRestrictions is an error"); - assert.commandFailed( - admin.runCommand({usersInfo: 1, showAuthenticationRestrictions: true})); - - print( - "Calling usersInfo for all users on a database with showAuthenticationRestrictions false or unset will succeed, and not produce authenticationRestriction fields"); - [{}, {showAuthenticationRestrictions: false}].forEach(function(fragment) { - forEachUser( - assert.commandWorked(admin.runCommand(Object.merge({usersInfo: 1}, fragment))), - function(userDoc) { - assert(!userDoc.hasOwnProperty("authenticationRestrictions")); - assert(!userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - }); - }); - - print( - "If usersInfo is called with showAuthenticationRestrictions true, on a user without authenticationRestrictions, a document with empty authenticationRestrictions and inheritedAuthenticationRestrictions arrays is returned"); - forEachUser(assert.commandWorked(admin.runCommand( - {usersInfo: "user", showAuthenticationRestrictions: true})), + var admin = conn.getDB("admin"); + assert(admin.auth("admin", "admin")); + + assert.commandWorked(admin.runCommand({createUser: "user", pwd: "pwd", roles: []})); + assert.commandWorked(admin.runCommand({ + createUser: "restrictedUser", + pwd: "pwd", + roles: [], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + assert.commandWorked(admin.runCommand({ + createRole: "restrictedRole", + roles: [], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.2"]}] + })); + assert.commandWorked(admin.runCommand( + {createUser: "userWithRestrictedRole", pwd: "pwd", roles: ["restrictedRole"]})); + assert.commandWorked(admin.runCommand({ + createUser: "restrictedUserWithRestrictedRole", + pwd: "pwd", + roles: ["restrictedRole"], + authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] + })); + + print( + "Calling usersInfo for all users on a database with showAuthenticationRestrictions is an error"); + assert.commandFailed(admin.runCommand({usersInfo: 1, showAuthenticationRestrictions: true})); + + print( + "Calling usersInfo for all users on a database with showAuthenticationRestrictions false or unset will succeed, and not produce authenticationRestriction fields"); + [{}, {showAuthenticationRestrictions: false}].forEach(function(fragment) { + forEachUser(assert.commandWorked(admin.runCommand(Object.merge({usersInfo: 1}, fragment))), function(userDoc) { - assert(userDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(0, userDoc["authenticationRestrictions"].length); - - assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(0, userDoc["inheritedAuthenticationRestrictions"].length); - }); - - print( - "If usersInfo is called and showAuthenticationRestrictions is false or unset, return a document without an authenticationRestrictions or inheritedAuthenticationRestrictions field"); - ["user", "restrictedUser", "userWithRestrictedRole", "restrictedUserWithRestrictedRole"] - .forEach(function(user) { - forEachUser( - assert.commandWorked(admin.runCommand( - {usersInfo: "user", showAuthenticationRestrictions: false})), - function(userDoc) { - assert(!userDoc.hasOwnProperty("authenticationRestrictions")); - assert(!userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - }); - forEachUser( - assert.commandWorked(admin.runCommand({usersInfo: "user"})), function(userDoc) { assert(!userDoc.hasOwnProperty("authenticationRestrictions")); assert(!userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); }); + }); - }); + print( + "If usersInfo is called with showAuthenticationRestrictions true, on a user without authenticationRestrictions, a document with empty authenticationRestrictions and inheritedAuthenticationRestrictions arrays is returned"); + forEachUser(assert.commandWorked( + admin.runCommand({usersInfo: "user", showAuthenticationRestrictions: true})), + function(userDoc) { + assert(userDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(0, userDoc["authenticationRestrictions"].length); - print( - "Authentication restrictions can be obtained through usersInfo for a single user with restrictions"); - forEachUser(assert.commandWorked(admin.runCommand( - {usersInfo: "restrictedUser", showAuthenticationRestrictions: true})), - function(userDoc) { - assert(userDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(1, userDoc["authenticationRestrictions"].length); + assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(0, userDoc["inheritedAuthenticationRestrictions"].length); + }); - assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(0, userDoc["inheritedAuthenticationRestrictions"].length); - }); + print( + "If usersInfo is called and showAuthenticationRestrictions is false or unset, return a document without an authenticationRestrictions or inheritedAuthenticationRestrictions field"); + ["user", "restrictedUser", "userWithRestrictedRole", "restrictedUserWithRestrictedRole"] + .forEach(function(user) { + forEachUser(assert.commandWorked(admin.runCommand( + {usersInfo: "user", showAuthenticationRestrictions: false})), + function(userDoc) { + assert(!userDoc.hasOwnProperty("authenticationRestrictions")); + assert(!userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + }); + forEachUser(assert.commandWorked(admin.runCommand({usersInfo: "user"})), + function(userDoc) { + assert(!userDoc.hasOwnProperty("authenticationRestrictions")); + assert(!userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + }); + }); - print( - "Authentication restrictions can be obtained through usersInfo for a single user with restrictioned roles"); - forEachUser( - assert.commandWorked(admin.runCommand( - {usersInfo: "userWithRestrictedRole", showAuthenticationRestrictions: true})), - function(userDoc) { - assert(userDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(0, userDoc["authenticationRestrictions"].length); - - assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(1, userDoc["inheritedAuthenticationRestrictions"].length); - }); - - print( - "Authentication restrictions can be obtained through usersInfo for a single restricted user with restrictioned roles"); - forEachUser(assert.commandWorked(admin.runCommand({ - usersInfo: "restrictedUserWithRestrictedRole", - showAuthenticationRestrictions: true - })), - function(userDoc) { - print("This doc: " + tojson(userDoc)); - assert(userDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(1, userDoc["authenticationRestrictions"].length); + print( + "Authentication restrictions can be obtained through usersInfo for a single user with restrictions"); + forEachUser(assert.commandWorked(admin.runCommand( + {usersInfo: "restrictedUser", showAuthenticationRestrictions: true})), + function(userDoc) { + assert(userDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(1, userDoc["authenticationRestrictions"].length); - assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(1, userDoc["inheritedAuthenticationRestrictions"].length); - }); - } + assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(0, userDoc["inheritedAuthenticationRestrictions"].length); + }); - function testRolesInfoCommand(conn) { - function forEachRole(res, assertFun) { - assert(res.hasOwnProperty("roles")); - print("Users: " + tojson(res.roles)); - assert.gt(res.roles.length, 0); - res.roles.forEach(assertFun); - } + print( + "Authentication restrictions can be obtained through usersInfo for a single user with restrictioned roles"); + forEachUser(assert.commandWorked(admin.runCommand( + {usersInfo: "userWithRestrictedRole", showAuthenticationRestrictions: true})), + function(userDoc) { + assert(userDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(0, userDoc["authenticationRestrictions"].length); - var admin = conn.getDB("admin"); - assert(admin.auth("admin", "admin")); + assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(1, userDoc["inheritedAuthenticationRestrictions"].length); + }); - assert.commandWorked(admin.runCommand({createRole: "role", roles: [], privileges: []})); - // restrictedRole already created + print( + "Authentication restrictions can be obtained through usersInfo for a single restricted user with restrictioned roles"); + forEachUser( assert.commandWorked(admin.runCommand( - {createRole: "roleWithRestrictedRole", roles: ["restrictedRole"], privileges: []})); - assert.commandWorked(admin.runCommand({ - createRole: "restrictedRoleWithRestrictedRole", - roles: ["restrictedRole"], - privileges: [], - authenticationRestrictions: [{clientSource: ["127.0.0.3"]}] - })); - - ["role", "restrictedRole", "roleWithRestrictedRole", "restrictedRoleWithRestrictedRole"] - .forEach(function(role) { - forEachRole( - assert.commandWorked(admin.runCommand({rolesInfo: role})), function(roleDoc) { - assert(!roleDoc.hasOwnProperty("authenticationRestrictions")); - assert(!roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - }); - }); - - forEachRole(assert.commandWorked(admin.runCommand( - {rolesInfo: "role", showAuthenticationRestrictions: true})), - function(roleDoc) { - assert(roleDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(0, roleDoc.authenticationRestrictions.length); - assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(0, roleDoc.inheritedAuthenticationRestrictions.length); - }); + {usersInfo: "restrictedUserWithRestrictedRole", showAuthenticationRestrictions: true})), + function(userDoc) { + print("This doc: " + tojson(userDoc)); + assert(userDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(1, userDoc["authenticationRestrictions"].length); + + assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(1, userDoc["inheritedAuthenticationRestrictions"].length); + }); +} + +function testRolesInfoCommand(conn) { + function forEachRole(res, assertFun) { + assert(res.hasOwnProperty("roles")); + print("Users: " + tojson(res.roles)); + assert.gt(res.roles.length, 0); + res.roles.forEach(assertFun); + } - forEachRole(assert.commandWorked(admin.runCommand( - {rolesInfo: "restrictedRole", showAuthenticationRestrictions: true})), - function(roleDoc) { - assert(roleDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(1, roleDoc.authenticationRestrictions.length); - assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(1, roleDoc.inheritedAuthenticationRestrictions.length); - }); + var admin = conn.getDB("admin"); + assert(admin.auth("admin", "admin")); + + assert.commandWorked(admin.runCommand({createRole: "role", roles: [], privileges: []})); + // restrictedRole already created + assert.commandWorked(admin.runCommand( + {createRole: "roleWithRestrictedRole", roles: ["restrictedRole"], privileges: []})); + assert.commandWorked(admin.runCommand({ + createRole: "restrictedRoleWithRestrictedRole", + roles: ["restrictedRole"], + privileges: [], + authenticationRestrictions: [{clientSource: ["127.0.0.3"]}] + })); + + ["role", "restrictedRole", "roleWithRestrictedRole", "restrictedRoleWithRestrictedRole"] + .forEach(function(role) { + forEachRole(assert.commandWorked(admin.runCommand({rolesInfo: role})), + function(roleDoc) { + assert(!roleDoc.hasOwnProperty("authenticationRestrictions")); + assert(!roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + }); + }); - forEachRole( - assert.commandWorked(admin.runCommand( - {rolesInfo: "roleWithRestrictedRole", showAuthenticationRestrictions: true})), - function(roleDoc) { - assert(roleDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(0, roleDoc.authenticationRestrictions.length); - assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(1, roleDoc.inheritedAuthenticationRestrictions.length); - }); - - forEachRole(assert.commandWorked(admin.runCommand({ - rolesInfo: "restrictedRoleWithRestrictedRole", - showAuthenticationRestrictions: true - })), - function(roleDoc) { - assert(roleDoc.hasOwnProperty("authenticationRestrictions")); - assert.eq(1, roleDoc.authenticationRestrictions.length); - assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); - assert.eq(2, roleDoc.inheritedAuthenticationRestrictions.length); - }); - } + forEachRole(assert.commandWorked( + admin.runCommand({rolesInfo: "role", showAuthenticationRestrictions: true})), + function(roleDoc) { + assert(roleDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(0, roleDoc.authenticationRestrictions.length); + assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(0, roleDoc.inheritedAuthenticationRestrictions.length); + }); + + forEachRole(assert.commandWorked(admin.runCommand( + {rolesInfo: "restrictedRole", showAuthenticationRestrictions: true})), + function(roleDoc) { + assert(roleDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(1, roleDoc.authenticationRestrictions.length); + assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(1, roleDoc.inheritedAuthenticationRestrictions.length); + }); + + forEachRole(assert.commandWorked(admin.runCommand( + {rolesInfo: "roleWithRestrictedRole", showAuthenticationRestrictions: true})), + function(roleDoc) { + assert(roleDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(0, roleDoc.authenticationRestrictions.length); + assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(1, roleDoc.inheritedAuthenticationRestrictions.length); + }); - var keyfile = "jstests/libs/key1"; - - print("Testing standalone"); - var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); - testRestrictionCreationAndEnforcement(conn, conn, function() {}, function() {}); - testUsersInfoCommand(conn); - testRolesInfoCommand(conn); - MongoRunner.stopMongod(conn); - - print("Testing replicaset"); - var rst = new ReplSetTest( - {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); - var nodes = rst.startSet(); - rst.initiate(); - rst.awaitSecondaryNodes(); - var awaitReplication = function() { - authutil.asCluster(nodes, "jstests/libs/key1", function() { - rst.awaitReplication(); + forEachRole( + assert.commandWorked(admin.runCommand( + {rolesInfo: "restrictedRoleWithRestrictedRole", showAuthenticationRestrictions: true})), + function(roleDoc) { + assert(roleDoc.hasOwnProperty("authenticationRestrictions")); + assert.eq(1, roleDoc.authenticationRestrictions.length); + assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); + assert.eq(2, roleDoc.inheritedAuthenticationRestrictions.length); }); - }; - - testRestrictionCreationAndEnforcement( - rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication); - testUsersInfoCommand(rst.getPrimary()); - testRolesInfoCommand(rst.getPrimary()); - rst.stopSet(); - - print("Testing sharded cluster"); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest({ - mongos: 2, - config: 3, - shard: 1, - keyFile: keyfile, - other: { - mongosOptions: {bind_ip_all: "", auth: null}, - configOptions: {auth: null}, - shardOptions: {auth: null}, - shardAsReplicaSet: false - } +} + +var keyfile = "jstests/libs/key1"; + +print("Testing standalone"); +var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); +testRestrictionCreationAndEnforcement(conn, conn, function() {}, function() {}); +testUsersInfoCommand(conn); +testRolesInfoCommand(conn); +MongoRunner.stopMongod(conn); + +print("Testing replicaset"); +var rst = new ReplSetTest( + {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); +var nodes = rst.startSet(); +rst.initiate(); +rst.awaitSecondaryNodes(); +var awaitReplication = function() { + authutil.asCluster(nodes, "jstests/libs/key1", function() { + rst.awaitReplication(); }); - testRestrictionCreationAndEnforcement( - st.s0, - st.s1, - function() {}, - function() { - sleep(40 * 1000); // Wait for mongos user cache invalidation - }); - testUsersInfoCommand(st.s0); - st.stop(); - +}; + +testRestrictionCreationAndEnforcement( + rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitReplication); +testUsersInfoCommand(rst.getPrimary()); +testRolesInfoCommand(rst.getPrimary()); +rst.stopSet(); + +print("Testing sharded cluster"); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest({ + mongos: 2, + config: 3, + shard: 1, + keyFile: keyfile, + other: { + mongosOptions: {bind_ip_all: "", auth: null}, + configOptions: {auth: null}, + shardOptions: {auth: null}, + shardAsReplicaSet: false + } +}); +testRestrictionCreationAndEnforcement( + st.s0, + st.s1, + function() {}, + function() { + sleep(40 * 1000); // Wait for mongos user cache invalidation + }); +testUsersInfoCommand(st.s0); +st.stop(); }()); diff --git a/jstests/auth/authz_modifications_access_control.js b/jstests/auth/authz_modifications_access_control.js index 11b9a59e593..f660e861908 100644 --- a/jstests/auth/authz_modifications_access_control.js +++ b/jstests/auth/authz_modifications_access_control.js @@ -70,7 +70,6 @@ function runTest(conn) { var roleObj = adminUserAdmin.system.roles.findOne({role: "readWrite", db: "admin"}); // double check that no role object named "readWrite" has been created assert(!roleObj, "user-defined \"readWrite\" role was created: " + tojson(roleObj)); - })(); (function testViewUser() { diff --git a/jstests/auth/autocomplete_auth.js b/jstests/auth/autocomplete_auth.js index c0057bf1e52..35450ecbca6 100644 --- a/jstests/auth/autocomplete_auth.js +++ b/jstests/auth/autocomplete_auth.js @@ -15,38 +15,38 @@ const self = this; (function() { - 'use strict'; +'use strict'; - const testName = jsTest.name(); - const conn = MongoRunner.runMongod({auth: ''}); - const admin = conn.getDB('admin'); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); +const testName = jsTest.name(); +const conn = MongoRunner.runMongod({auth: ''}); +const admin = conn.getDB('admin'); +admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +assert(admin.auth('admin', 'pass')); - admin.getSiblingDB(testName).createRole({ - role: 'coachTicket', - privileges: [{resource: {db: testName, collection: 'coachClass'}, actions: ['find']}], - roles: [] - }); +admin.getSiblingDB(testName).createRole({ + role: 'coachTicket', + privileges: [{resource: {db: testName, collection: 'coachClass'}, actions: ['find']}], + roles: [] +}); - admin.getSiblingDB(testName).createUser( - {user: 'coachPassenger', pwd: 'password', roles: ['coachTicket']}); +admin.getSiblingDB(testName).createUser( + {user: 'coachPassenger', pwd: 'password', roles: ['coachTicket']}); - const testDB = conn.getDB(testName); - testDB.coachClass.insertOne({}); - testDB.businessClass.insertOne({}); +const testDB = conn.getDB(testName); +testDB.coachClass.insertOne({}); +testDB.businessClass.insertOne({}); - // Must use 'db' to test autocompletion. - self.db = new Mongo(conn.host).getDB(testName); - assert(db.auth('coachPassenger', 'password')); - const authzErrorCode = 13; - assert.commandFailedWithCode(db.runCommand({listCollections: 1}), authzErrorCode); - assert.commandWorked(db.runCommand({find: 'coachClass'})); - assert.commandFailedWithCode(db.runCommand({find: 'businessClass'}), authzErrorCode); - shellAutocomplete('db.'); - assert(__autocomplete__.includes('db.coachClass'), - `Completions should include 'coachClass': ${__autocomplete__}`); - assert(!__autocomplete__.includes('db.businessClass'), - `Completions should NOT include 'businessClass': ${__autocomplete__}`); - MongoRunner.stopMongod(conn); +// Must use 'db' to test autocompletion. +self.db = new Mongo(conn.host).getDB(testName); +assert(db.auth('coachPassenger', 'password')); +const authzErrorCode = 13; +assert.commandFailedWithCode(db.runCommand({listCollections: 1}), authzErrorCode); +assert.commandWorked(db.runCommand({find: 'coachClass'})); +assert.commandFailedWithCode(db.runCommand({find: 'businessClass'}), authzErrorCode); +shellAutocomplete('db.'); +assert(__autocomplete__.includes('db.coachClass'), + `Completions should include 'coachClass': ${__autocomplete__}`); +assert(!__autocomplete__.includes('db.businessClass'), + `Completions should NOT include 'businessClass': ${__autocomplete__}`); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/basic_role_auth.js b/jstests/auth/basic_role_auth.js index e610d1ed493..6f481afc2e6 100644 --- a/jstests/auth/basic_role_auth.js +++ b/jstests/auth/basic_role_auth.js @@ -231,215 +231,215 @@ var testOps = function(db, allowedActions) { // } var TESTS = [ { - name: 'Test multiple user login separate connection', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); - - var conn2 = new Mongo(conn.host); - var testDB2 = conn2.getDB('test'); - assert.eq(1, testDB2.auth('uadmin', AUTH_INFO.test.uadmin.pwd)); - - testOps(testDB, READ_PERM); - testOps(testDB2, UADMIN_PERM); - } + name: 'Test multiple user login separate connection', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); + + var conn2 = new Mongo(conn.host); + var testDB2 = conn2.getDB('test'); + assert.eq(1, testDB2.auth('uadmin', AUTH_INFO.test.uadmin.pwd)); + + testOps(testDB, READ_PERM); + testOps(testDB2, UADMIN_PERM); + } }, { - name: 'Test user with no role', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('none', AUTH_INFO.test.none.pwd)); + name: 'Test user with no role', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('none', AUTH_INFO.test.none.pwd)); - testOps(testDB, {}); - } + testOps(testDB, {}); + } }, { - name: 'Test read only user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); + name: 'Test read only user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); - testOps(testDB, READ_PERM); - } + testOps(testDB, READ_PERM); + } }, { - name: 'Test read/write user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); + name: 'Test read/write user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); - testOps(testDB, READ_WRITE_PERM); - } + testOps(testDB, READ_WRITE_PERM); + } }, { - name: 'Test read + dbAdmin user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('roadmin', AUTH_INFO.test.roadmin.pwd)); - - var combinedPerm = Object.extend({}, READ_PERM); - combinedPerm = Object.extend(combinedPerm, ADMIN_PERM); - testOps(testDB, combinedPerm); - } + name: 'Test read + dbAdmin user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('roadmin', AUTH_INFO.test.roadmin.pwd)); + + var combinedPerm = Object.extend({}, READ_PERM); + combinedPerm = Object.extend(combinedPerm, ADMIN_PERM); + testOps(testDB, combinedPerm); + } }, { - name: 'Test dbAdmin user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('admin', AUTH_INFO.test.admin.pwd)); + name: 'Test dbAdmin user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('admin', AUTH_INFO.test.admin.pwd)); - testOps(testDB, ADMIN_PERM); - } + testOps(testDB, ADMIN_PERM); + } }, { - name: 'Test userAdmin user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('uadmin', AUTH_INFO.test.uadmin.pwd)); + name: 'Test userAdmin user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('uadmin', AUTH_INFO.test.uadmin.pwd)); - testOps(testDB, UADMIN_PERM); - } + testOps(testDB, UADMIN_PERM); + } }, { - name: 'Test cluster user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('cluster', AUTH_INFO.admin.cluster.pwd)); + name: 'Test cluster user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('cluster', AUTH_INFO.admin.cluster.pwd)); - testOps(conn.getDB('test'), CLUSTER_PERM); - } + testOps(conn.getDB('test'), CLUSTER_PERM); + } }, { - name: 'Test admin user with no role', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('anone', AUTH_INFO.admin.anone.pwd)); - - testOps(adminDB, {}); - testOps(conn.getDB('test'), {}); - } + name: 'Test admin user with no role', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('anone', AUTH_INFO.admin.anone.pwd)); + + testOps(adminDB, {}); + testOps(conn.getDB('test'), {}); + } }, { - name: 'Test read only admin user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('aro', AUTH_INFO.admin.aro.pwd)); - - testOps(adminDB, READ_PERM); - testOps(conn.getDB('test'), {}); - } + name: 'Test read only admin user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('aro', AUTH_INFO.admin.aro.pwd)); + + testOps(adminDB, READ_PERM); + testOps(conn.getDB('test'), {}); + } }, { - name: 'Test read/write admin user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('arw', AUTH_INFO.admin.arw.pwd)); - - testOps(adminDB, READ_WRITE_PERM); - testOps(conn.getDB('test'), {}); - } + name: 'Test read/write admin user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('arw', AUTH_INFO.admin.arw.pwd)); + + testOps(adminDB, READ_WRITE_PERM); + testOps(conn.getDB('test'), {}); + } }, { - name: 'Test dbAdmin admin user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('aadmin', AUTH_INFO.admin.aadmin.pwd)); - - testOps(adminDB, ADMIN_PERM); - testOps(conn.getDB('test'), {}); - } + name: 'Test dbAdmin admin user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('aadmin', AUTH_INFO.admin.aadmin.pwd)); + + testOps(adminDB, ADMIN_PERM); + testOps(conn.getDB('test'), {}); + } }, { - name: 'Test userAdmin admin user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('auadmin', AUTH_INFO.admin.auadmin.pwd)); - - testOps(adminDB, UADMIN_PERM); - testOps(conn.getDB('test'), {}); - } + name: 'Test userAdmin admin user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('auadmin', AUTH_INFO.admin.auadmin.pwd)); + + testOps(adminDB, UADMIN_PERM); + testOps(conn.getDB('test'), {}); + } }, { - name: 'Test read only any db user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('any_ro', AUTH_INFO.admin.any_ro.pwd)); - - testOps(adminDB, READ_PERM); - testOps(conn.getDB('test'), READ_PERM); - } + name: 'Test read only any db user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('any_ro', AUTH_INFO.admin.any_ro.pwd)); + + testOps(adminDB, READ_PERM); + testOps(conn.getDB('test'), READ_PERM); + } }, { - name: 'Test read/write any db user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('any_rw', AUTH_INFO.admin.any_rw.pwd)); - - testOps(adminDB, READ_WRITE_PERM); - testOps(conn.getDB('test'), READ_WRITE_PERM); - } + name: 'Test read/write any db user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('any_rw', AUTH_INFO.admin.any_rw.pwd)); + + testOps(adminDB, READ_WRITE_PERM); + testOps(conn.getDB('test'), READ_WRITE_PERM); + } }, { - name: 'Test dbAdmin any db user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('any_admin', AUTH_INFO.admin.any_admin.pwd)); - - testOps(adminDB, ADMIN_PERM); - testOps(conn.getDB('test'), ADMIN_PERM); - } + name: 'Test dbAdmin any db user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('any_admin', AUTH_INFO.admin.any_admin.pwd)); + + testOps(adminDB, ADMIN_PERM); + testOps(conn.getDB('test'), ADMIN_PERM); + } }, { - name: 'Test userAdmin any db user', - test: function(conn) { - var adminDB = conn.getDB('admin'); - assert.eq(1, adminDB.auth('any_uadmin', AUTH_INFO.admin.any_uadmin.pwd)); - - testOps(adminDB, UADMIN_PERM); - testOps(conn.getDB('test'), UADMIN_PERM); - } + name: 'Test userAdmin any db user', + test: function(conn) { + var adminDB = conn.getDB('admin'); + assert.eq(1, adminDB.auth('any_uadmin', AUTH_INFO.admin.any_uadmin.pwd)); + + testOps(adminDB, UADMIN_PERM); + testOps(conn.getDB('test'), UADMIN_PERM); + } }, { - name: 'Test change role', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); - - var newConn = new Mongo(conn.host); - assert.eq(1, newConn.getDB('admin').auth('any_uadmin', AUTH_INFO.admin.any_uadmin.pwd)); - newConn.getDB('test').updateUser('rw', {roles: ['read']}); - var origSpec = newConn.getDB("test").getUser("rw"); - - // role change should affect users already authenticated. - testOps(testDB, READ_PERM); - - // role change should affect active connections. - testDB.runCommand({logout: 1}); - assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); - testOps(testDB, READ_PERM); - - // role change should also affect new connections. - var newConn3 = new Mongo(conn.host); - var testDB3 = newConn3.getDB('test'); - assert.eq(1, testDB3.auth('rw', AUTH_INFO.test.rw.pwd)); - testOps(testDB3, READ_PERM); - - newConn.getDB('test').updateUser('rw', {roles: origSpec.roles}); - } + name: 'Test change role', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); + + var newConn = new Mongo(conn.host); + assert.eq(1, newConn.getDB('admin').auth('any_uadmin', AUTH_INFO.admin.any_uadmin.pwd)); + newConn.getDB('test').updateUser('rw', {roles: ['read']}); + var origSpec = newConn.getDB("test").getUser("rw"); + + // role change should affect users already authenticated. + testOps(testDB, READ_PERM); + + // role change should affect active connections. + testDB.runCommand({logout: 1}); + assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); + testOps(testDB, READ_PERM); + + // role change should also affect new connections. + var newConn3 = new Mongo(conn.host); + var testDB3 = newConn3.getDB('test'); + assert.eq(1, testDB3.auth('rw', AUTH_INFO.test.rw.pwd)); + testOps(testDB3, READ_PERM); + + newConn.getDB('test').updateUser('rw', {roles: origSpec.roles}); + } }, { - name: 'Test override user', - test: function(conn) { - var testDB = conn.getDB('test'); - assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); - assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); - testOps(testDB, READ_PERM); - - testDB.runCommand({logout: 1}); - testOps(testDB, {}); - } + name: 'Test override user', + test: function(conn) { + var testDB = conn.getDB('test'); + assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); + assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); + testOps(testDB, READ_PERM); + + testDB.runCommand({logout: 1}); + testOps(testDB, {}); + } } ]; diff --git a/jstests/auth/cluster_ip_whitelist.js b/jstests/auth/cluster_ip_whitelist.js index b82262a7551..401133dcf71 100644 --- a/jstests/auth/cluster_ip_whitelist.js +++ b/jstests/auth/cluster_ip_whitelist.js @@ -3,55 +3,54 @@ */ (function() { - 'use strict'; - - print("When whitelist is empty, the server does not start."); - assert.eq(null, - MongoRunner.runMongod( - {auth: null, keyFile: "jstests/libs/key1", clusterIpSourceWhitelist: ""})); - - function testIpWhitelist(description, whitelistString, authResult) { - print(description); - - var conn = MongoRunner.runMongod( - {auth: null, keyFile: "jstests/libs/key1", clusterIpSourceWhitelist: whitelistString}); - assert.eq(authResult, conn.getDB("local").auth("__system", "foopdedoop")); - MongoRunner.stopMongod(conn); - } - - testIpWhitelist( - "When 127.0.0.1 is whitelisted, a client connected via localhost may auth as __system.", - "127.0.0.1", - true); - - testIpWhitelist( - "When 127.0.0.0 is whitelisted as a 24-bit CIDR block, a client connected via localhost may auth as __system.", - "127.0.0.0/24", - true); - - testIpWhitelist( - "When 127.0.0.5 is whitelisted as a 24-bit CIDR block, a client connected via localhost may auth as __system.", - "127.0.0.5/24", - true); - - testIpWhitelist( - "When 127.0.0.0 is whitelisted as a 8-bit CIDR block, a client connected via localhost may auth as __system.", - "127.0.0.0/8", - true); - - testIpWhitelist( - "When the IP block reserved for documentation and the 127.0.0.0/8 block are both whitelisted, a client connected via localhost may auth as __system.", - "192.0.2.0/24,127.0.0.0/8", - true); - - testIpWhitelist( - "When 127.0.0.0/8 and the IP block reserved for documentation are both whitelisted, a client connected via localhost may auth as __system.", - "127.0.0.0/8,192.0.2.0/24", - true); - - testIpWhitelist( - "When the IP block reserved for documentation and examples is whitelisted, a client connected via localhost may not auth as __system.", - "192.0.2.0/24", - false); - +'use strict'; + +print("When whitelist is empty, the server does not start."); +assert.eq(null, + MongoRunner.runMongod( + {auth: null, keyFile: "jstests/libs/key1", clusterIpSourceWhitelist: ""})); + +function testIpWhitelist(description, whitelistString, authResult) { + print(description); + + var conn = MongoRunner.runMongod( + {auth: null, keyFile: "jstests/libs/key1", clusterIpSourceWhitelist: whitelistString}); + assert.eq(authResult, conn.getDB("local").auth("__system", "foopdedoop")); + MongoRunner.stopMongod(conn); +} + +testIpWhitelist( + "When 127.0.0.1 is whitelisted, a client connected via localhost may auth as __system.", + "127.0.0.1", + true); + +testIpWhitelist( + "When 127.0.0.0 is whitelisted as a 24-bit CIDR block, a client connected via localhost may auth as __system.", + "127.0.0.0/24", + true); + +testIpWhitelist( + "When 127.0.0.5 is whitelisted as a 24-bit CIDR block, a client connected via localhost may auth as __system.", + "127.0.0.5/24", + true); + +testIpWhitelist( + "When 127.0.0.0 is whitelisted as a 8-bit CIDR block, a client connected via localhost may auth as __system.", + "127.0.0.0/8", + true); + +testIpWhitelist( + "When the IP block reserved for documentation and the 127.0.0.0/8 block are both whitelisted, a client connected via localhost may auth as __system.", + "192.0.2.0/24,127.0.0.0/8", + true); + +testIpWhitelist( + "When 127.0.0.0/8 and the IP block reserved for documentation are both whitelisted, a client connected via localhost may auth as __system.", + "127.0.0.0/8,192.0.2.0/24", + true); + +testIpWhitelist( + "When the IP block reserved for documentation and examples is whitelisted, a client connected via localhost may not auth as __system.", + "192.0.2.0/24", + false); }()); diff --git a/jstests/auth/commands_builtin_roles.js b/jstests/auth/commands_builtin_roles.js index 32674cd8a41..0c87ea82763 100644 --- a/jstests/auth/commands_builtin_roles.js +++ b/jstests/auth/commands_builtin_roles.js @@ -58,15 +58,16 @@ function testProperAuthorization(conn, t, testcase, r) { assert(r.db.auth("user|" + r.key, "password")); authCommandsLib.authenticatedSetup(t, runOnDb); var command = t.command; - if (typeof(command) === "function") { + if (typeof (command) === "function") { command = t.command(state, testcase.commandArgs); } var res = runOnDb.runCommand(command); if (testcase.roles[r.key]) { if (res.ok == 0 && res.code == authErrCode) { - out = "expected authorization success" + " but received " + tojson(res) + " on db " + - testcase.runOnDb + " with role " + r.key; + out = "expected authorization success" + + " but received " + tojson(res) + " on db " + testcase.runOnDb + " with role " + + r.key; } else if (res.ok == 0 && !testcase.expectFail && res.code != commandNotSupportedCode) { // don't error if the test failed with code commandNotSupported since // some storage engines (e.g wiredTiger) don't support some commands (e.g. touch) @@ -75,8 +76,9 @@ function testProperAuthorization(conn, t, testcase, r) { } } else { if (res.ok == 1 || (res.ok == 0 && res.code != authErrCode)) { - out = "expected authorization failure" + " but received result " + tojson(res) + - " on db " + testcase.runOnDb + " with role " + r.key; + out = "expected authorization failure" + + " but received result " + tojson(res) + " on db " + testcase.runOnDb + + " with role " + r.key; } } diff --git a/jstests/auth/commands_user_defined_roles.js b/jstests/auth/commands_user_defined_roles.js index 049034f4c86..003957abe64 100644 --- a/jstests/auth/commands_user_defined_roles.js +++ b/jstests/auth/commands_user_defined_roles.js @@ -40,7 +40,7 @@ function testProperAuthorization(conn, t, testcase, privileges) { authCommandsLib.authenticatedSetup(t, runOnDb); var command = t.command; - if (typeof(command) === "function") { + if (typeof (command) === "function") { command = t.command(state, testcase.commandArgs); } var res = runOnDb.runCommand(command); @@ -51,8 +51,9 @@ function testProperAuthorization(conn, t, testcase, privileges) { out = "command failed with " + tojson(res) + " on db " + testcase.runOnDb + " with privileges " + tojson(privileges); } else if (testcase.expectFail && res.code == authErrCode) { - out = "expected authorization success" + " but received " + tojson(res) + " on db " + - testcase.runOnDb + " with privileges " + tojson(privileges); + out = "expected authorization success" + + " but received " + tojson(res) + " on db " + testcase.runOnDb + " with privileges " + + tojson(privileges); } firstDb.logout(); @@ -78,14 +79,14 @@ function testInsufficientPrivileges(conn, t, testcase, privileges) { authCommandsLib.authenticatedSetup(t, runOnDb); var command = t.command; - if (typeof(command) === "function") { + if (typeof (command) === "function") { command = t.command(state, testcase.commandArgs); } var res = runOnDb.runCommand(command); if (res.ok == 1 || res.code != authErrCode) { - out = "expected authorization failure " + " but received " + tojson(res) + - " with privileges " + tojson(privileges); + out = "expected authorization failure " + + " but received " + tojson(res) + " with privileges " + tojson(privileges); } firstDb.logout(); diff --git a/jstests/auth/curop_auth_info.js b/jstests/auth/curop_auth_info.js index 94f7426e4f1..2bb329b1eee 100644 --- a/jstests/auth/curop_auth_info.js +++ b/jstests/auth/curop_auth_info.js @@ -1,77 +1,77 @@ (function() { - 'use strict'; +'use strict'; - const runTest = function(conn, failPointConn) { - jsTestLog("Setting up users"); - const db = conn.getDB("admin"); - assert.commandWorked( - db.runCommand({createUser: "admin", pwd: "pwd", roles: jsTest.adminUserRoles})); - assert.eq(db.auth("admin", "pwd"), 1); - assert.commandWorked(db.runCommand({createUser: "testuser", pwd: "pwd", roles: []})); - db.grantRolesToUser("testuser", [{role: "readWrite", db: "test"}]); +const runTest = function(conn, failPointConn) { + jsTestLog("Setting up users"); + const db = conn.getDB("admin"); + assert.commandWorked( + db.runCommand({createUser: "admin", pwd: "pwd", roles: jsTest.adminUserRoles})); + assert.eq(db.auth("admin", "pwd"), 1); + assert.commandWorked(db.runCommand({createUser: "testuser", pwd: "pwd", roles: []})); + db.grantRolesToUser("testuser", [{role: "readWrite", db: "test"}]); - const queryFn = function() { - assert.eq(db.getSiblingDB("admin").auth("testuser", "pwd"), 1); - let testDB = db.getSiblingDB("test"); - testDB.test.insert({}); - assert.eq(testDB.test.find({}).comment("curop_auth_info.js query").itcount(), 1); - }; - - jsTestLog("blocking finds and starting parallel shell to create op"); - assert.commandWorked(failPointConn.getDB("admin").runCommand( - {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "alwaysOn"})); - let finderWait = startParallelShell(queryFn, conn.port); - let myOp; + const queryFn = function() { + assert.eq(db.getSiblingDB("admin").auth("testuser", "pwd"), 1); + let testDB = db.getSiblingDB("test"); + testDB.test.insert({}); + assert.eq(testDB.test.find({}).comment("curop_auth_info.js query").itcount(), 1); + }; - assert.soon(function() { - const curOpResults = db.runCommand({currentOp: 1}); - assert.commandWorked(curOpResults); - print(tojson(curOpResults)); - const myOps = curOpResults["inprog"].filter((op) => { - return (op["command"]["comment"] == "curop_auth_info.js query"); - }); + jsTestLog("blocking finds and starting parallel shell to create op"); + assert.commandWorked(failPointConn.getDB("admin").runCommand( + {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "alwaysOn"})); + let finderWait = startParallelShell(queryFn, conn.port); + let myOp; - if (myOps.length == 0) { - return false; - } - myOp = myOps[0]; - return true; + assert.soon(function() { + const curOpResults = db.runCommand({currentOp: 1}); + assert.commandWorked(curOpResults); + print(tojson(curOpResults)); + const myOps = curOpResults["inprog"].filter((op) => { + return (op["command"]["comment"] == "curop_auth_info.js query"); }); - jsTestLog("found op"); - assert.commandWorked(failPointConn.getDB("admin").runCommand( - {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "off"})); - finderWait(); - - const authedUsers = myOp["effectiveUsers"]; - const impersonators = myOp["runBy"]; - print(tojson(authedUsers), tojson(impersonators)); - if (impersonators) { - assert.eq(authedUsers.length, 1); - assert.docEq(authedUsers[0], {user: "testuser", db: "admin"}); - assert(impersonators); - assert.eq(impersonators.length, 1); - assert.docEq(impersonators[0], {user: "__system", db: "local"}); - } else { - assert(authedUsers); - assert.eq(authedUsers.length, 1); - assert.docEq(authedUsers[0], {user: "testuser", db: "admin"}); + if (myOps.length == 0) { + return false; } - }; + myOp = myOps[0]; + return true; + }); - const m = MongoRunner.runMongod(); - runTest(m, m); - MongoRunner.stopMongod(m); + jsTestLog("found op"); + assert.commandWorked(failPointConn.getDB("admin").runCommand( + {configureFailPoint: "waitInFindBeforeMakingBatch", mode: "off"})); + finderWait(); - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - keyFile: 'jstests/libs/key1', - other: { - shardAsReplicaSet: false, - } - }); - runTest(st.s0, st.d0); - st.stop(); + const authedUsers = myOp["effectiveUsers"]; + const impersonators = myOp["runBy"]; + print(tojson(authedUsers), tojson(impersonators)); + if (impersonators) { + assert.eq(authedUsers.length, 1); + assert.docEq(authedUsers[0], {user: "testuser", db: "admin"}); + assert(impersonators); + assert.eq(impersonators.length, 1); + assert.docEq(impersonators[0], {user: "__system", db: "local"}); + } else { + assert(authedUsers); + assert.eq(authedUsers.length, 1); + assert.docEq(authedUsers[0], {user: "testuser", db: "admin"}); + } +}; + +const m = MongoRunner.runMongod(); +runTest(m, m); +MongoRunner.stopMongod(m); + +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + keyFile: 'jstests/libs/key1', + other: { + shardAsReplicaSet: false, + } +}); +runTest(st.s0, st.d0); +st.stop(); })(); diff --git a/jstests/auth/currentop_cursors_auth.js b/jstests/auth/currentop_cursors_auth.js index ca196be176f..70ee354273a 100644 --- a/jstests/auth/currentop_cursors_auth.js +++ b/jstests/auth/currentop_cursors_auth.js @@ -4,164 +4,156 @@ * @tags: [assumes_read_concern_unchanged, requires_auth, requires_journaling, requires_replication] */ (function() { - "use strict"; +"use strict"; - load("jstests/libs/fixture_helpers.js"); // For isMongos. +load("jstests/libs/fixture_helpers.js"); // For isMongos. - // TODO SERVER-32672: remove the 'skipGossipingClusterTime' flag. - TestData.skipGossipingClusterTime = true; +// 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}); +// 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; +const shardConn = st.rs0.getPrimary(); +const mongosConn = st.s; - shardConn.waitForClusterTime(60); +shardConn.waitForClusterTime(60); - Random.setRandomSeed(); - const pass = "a" + Random.rand(); +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 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); +// Create the necessary users at both cluster and shard-local level. +createUsers(shardConn); +createUsers(mongosConn); - // 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"); +// 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"); - result = adminDB + // 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); + 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); + } - // Confirm that the root user can see both users' cursors with {allUsers: true}. + // 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: true, allUsers: true, idleCursors: true}}, - { - $match: { - type: "idleCursor", - "cursor.cursorId": {$in: [cursorId, secondCursorId]} - } - } + {$currentOp: {localOps: false, allUsers: true, idleCursors: true}}, + {$match: {type: "idleCursor", shard: st.rs0.name}} ]) .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); + // 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); +jsTestLog("Running cursor tests on mongoS"); +runCursorTests(mongosConn); - st.stop(); +st.stop(); })(); diff --git a/jstests/auth/deleted_recreated_user.js b/jstests/auth/deleted_recreated_user.js index 87517f48297..704710107c0 100644 --- a/jstests/auth/deleted_recreated_user.js +++ b/jstests/auth/deleted_recreated_user.js @@ -1,74 +1,74 @@ // Test that sessions can not be resumed by deleted and recreated user. (function() { - 'use strict'; +'use strict'; - const kInvalidationIntervalSecs = 5; +const kInvalidationIntervalSecs = 5; - function runTest(s0, s1) { - assert(s0); - assert(s1); - const admin = s0.getDB('admin'); +function runTest(s0, s1) { + assert(s0); + assert(s1); + const admin = s0.getDB('admin'); - function checkIdType(username) { - const user = admin.system.users.find({user: username, db: 'admin'}).toArray()[0]; - const id = user._id; - const userId = user.userId; - assert.eq(typeof(id), 'string'); - assert.eq(id, 'admin.' + username); - assert.eq(typeof(userId), 'object'); - assert.eq(tojson(userId).substring(0, 5), 'UUID('); - } - - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - checkIdType('admin'); + function checkIdType(username) { + const user = admin.system.users.find({user: username, db: 'admin'}).toArray()[0]; + const id = user._id; + const userId = user.userId; + assert.eq(typeof (id), 'string'); + assert.eq(id, 'admin.' + username); + assert.eq(typeof (userId), 'object'); + assert.eq(tojson(userId).substring(0, 5), 'UUID('); + } - admin.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); - checkIdType('user'); - admin.logout(); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + checkIdType('admin'); - // Connect as basic user and create a session. - assert(admin.auth('user', 'pass')); - assert.writeOK(admin.mycoll.insert({_id: "foo", data: "bar"})); + admin.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); + checkIdType('user'); + admin.logout(); - // Perform administrative commands via separate shell. - function evalCmd(cmd) { - const uri = 'mongodb://admin:pass@localhost:' + s1.port + '/admin'; - const result = runMongoProgram('./mongo', uri, '--eval', cmd); - assert.eq(result, 0, "Command failed"); - } - evalCmd('db.dropUser("user"); '); - evalCmd('db.createUser({user: "user", pwd: "secret", roles: ["root"]});'); + // Connect as basic user and create a session. + assert(admin.auth('user', 'pass')); + assert.writeOK(admin.mycoll.insert({_id: "foo", data: "bar"})); - if (s0 !== s1) { - // Wait for twice the invalidation interval when sharding. - sleep(2 * kInvalidationIntervalSecs * 1000); - } + // Perform administrative commands via separate shell. + function evalCmd(cmd) { + const uri = 'mongodb://admin:pass@localhost:' + s1.port + '/admin'; + const result = runMongoProgram('./mongo', uri, '--eval', cmd); + assert.eq(result, 0, "Command failed"); + } + evalCmd('db.dropUser("user"); '); + evalCmd('db.createUser({user: "user", pwd: "secret", roles: ["root"]});'); - // This should fail due to invalid user session. - const thrown = - assert.throws(() => admin.mycoll.find({}).toArray(), [], "Able to find after recreate"); - assert.eq(thrown.code, ErrorCodes.Unauthorized, "Threw something other than unauthorized"); + if (s0 !== s1) { + // Wait for twice the invalidation interval when sharding. + sleep(2 * kInvalidationIntervalSecs * 1000); } - const mongod = MongoRunner.runMongod({auth: ''}); - runTest(mongod, mongod); - MongoRunner.stopMongod(mongod); + // This should fail due to invalid user session. + const thrown = + assert.throws(() => admin.mycoll.find({}).toArray(), [], "Able to find after recreate"); + assert.eq(thrown.code, ErrorCodes.Unauthorized, "Threw something other than unauthorized"); +} + +const mongod = MongoRunner.runMongod({auth: ''}); +runTest(mongod, mongod); +MongoRunner.stopMongod(mongod); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 2, - config: 1, - other: { - keyFile: 'jstests/libs/key1', - shardAsReplicaSet: false, - mongosOptions: { - setParameter: 'userCacheInvalidationIntervalSecs=' + kInvalidationIntervalSecs, - }, +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 2, + config: 1, + other: { + keyFile: 'jstests/libs/key1', + shardAsReplicaSet: false, + mongosOptions: { + setParameter: 'userCacheInvalidationIntervalSecs=' + kInvalidationIntervalSecs, }, - }); - runTest(st.s0, st.s1); - st.stop(); + }, +}); +runTest(st.s0, st.s1); +st.stop(); })(); 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(); }()); diff --git a/jstests/auth/iteration_count_control.js b/jstests/auth/iteration_count_control.js index 6ae57fdd6f7..d003347bdbc 100644 --- a/jstests/auth/iteration_count_control.js +++ b/jstests/auth/iteration_count_control.js @@ -1,43 +1,43 @@ // Test SCRAM iterationCount control. (function() { - 'use strict'; +'use strict'; - load('./jstests/multiVersion/libs/auth_helpers.js'); +load('./jstests/multiVersion/libs/auth_helpers.js'); - const conn = MongoRunner.runMongod({auth: ''}); - const adminDB = conn.getDB('admin'); +const conn = MongoRunner.runMongod({auth: ''}); +const adminDB = conn.getDB('admin'); - adminDB.createUser({user: 'user1', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(adminDB.auth({user: 'user1', pwd: 'pass'})); +adminDB.createUser({user: 'user1', pwd: 'pass', roles: jsTest.adminUserRoles}); +assert(adminDB.auth({user: 'user1', pwd: 'pass'})); - var userDoc = getUserDoc(adminDB, 'user1'); - assert.eq(10000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); +var userDoc = getUserDoc(adminDB, 'user1'); +assert.eq(10000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); - // Changing iterationCount should not affect existing users. - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 5000})); - userDoc = getUserDoc(adminDB, 'user1'); - assert.eq(10000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); +// Changing iterationCount should not affect existing users. +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 5000})); +userDoc = getUserDoc(adminDB, 'user1'); +assert.eq(10000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); - // But it should take effect when the user's password is changed. - adminDB.updateUser('user1', {pwd: 'pass', roles: jsTest.adminUserRoles}); - userDoc = getUserDoc(adminDB, 'user1'); - assert.eq(5000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); +// But it should take effect when the user's password is changed. +adminDB.updateUser('user1', {pwd: 'pass', roles: jsTest.adminUserRoles}); +userDoc = getUserDoc(adminDB, 'user1'); +assert.eq(5000, userDoc.credentials['SCRAM-SHA-1'].iterationCount); - // Test (in)valid values for scramIterationCount. 5000 is the minimum value. - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramIterationCount: 4999})); - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramIterationCount: -5000})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 5000})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 10000})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 1000000})); +// Test (in)valid values for scramIterationCount. 5000 is the minimum value. +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramIterationCount: 4999})); +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramIterationCount: -5000})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 5000})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 10000})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramIterationCount: 1000000})); - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: -5000})); - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4095})); - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4096})); - assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4999})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 5000})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 10000})); - assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 1000000})); +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: -5000})); +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4095})); +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4096})); +assert.commandFailed(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 4999})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 5000})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 10000})); +assert.commandWorked(adminDB.runCommand({setParameter: 1, scramSHA256IterationCount: 1000000})); - MongoRunner.stopMongod(conn); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/iteration_count_defaults.js b/jstests/auth/iteration_count_defaults.js index 6ebe74abec1..560704e274c 100644 --- a/jstests/auth/iteration_count_defaults.js +++ b/jstests/auth/iteration_count_defaults.js @@ -1,28 +1,28 @@ // Test SCRAM iterationCount defaults. (function() { - 'use strict'; +'use strict'; - function runOpt(params, sha1Value, sha256Value) { - const conn = MongoRunner.runMongod({auth: '', setParameter: params}); - const adminDB = conn.getDB('admin'); +function runOpt(params, sha1Value, sha256Value) { + const conn = MongoRunner.runMongod({auth: '', setParameter: params}); + const adminDB = conn.getDB('admin'); - adminDB.createUser({user: 'user1', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(adminDB.auth({user: 'user1', pwd: 'pass'})); + adminDB.createUser({user: 'user1', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(adminDB.auth({user: 'user1', pwd: 'pass'})); - const response = assert.commandWorked(adminDB.runCommand( - {getParameter: 1, scramIterationCount: 1, scramSHA256IterationCount: 1})); - assert.eq(response.scramIterationCount, sha1Value); - assert.eq(response.scramSHA256IterationCount, sha256Value); + const response = assert.commandWorked(adminDB.runCommand( + {getParameter: 1, scramIterationCount: 1, scramSHA256IterationCount: 1})); + assert.eq(response.scramIterationCount, sha1Value); + assert.eq(response.scramSHA256IterationCount, sha256Value); - MongoRunner.stopMongod(conn); - } + MongoRunner.stopMongod(conn); +} - runOpt({}, 10000, 15000); - runOpt({scramIterationCount: 12500}, 12500, 15000); - runOpt({scramIterationCount: 20000}, 20000, 20000); - runOpt({scramSHA256IterationCount: 9999}, 10000, 9999); - runOpt({scramSHA256IterationCount: 10001}, 10000, 10001); - runOpt({scramIterationCount: 7000, scramSHA256IterationCount: 8000}, 7000, 8000); - runOpt({scramIterationCount: 8000, scramSHA256IterationCount: 7000}, 8000, 7000); +runOpt({}, 10000, 15000); +runOpt({scramIterationCount: 12500}, 12500, 15000); +runOpt({scramIterationCount: 20000}, 20000, 20000); +runOpt({scramSHA256IterationCount: 9999}, 10000, 9999); +runOpt({scramSHA256IterationCount: 10001}, 10000, 10001); +runOpt({scramIterationCount: 7000, scramSHA256IterationCount: 8000}, 7000, 8000); +runOpt({scramIterationCount: 8000, scramSHA256IterationCount: 7000}, 8000, 7000); })(); diff --git a/jstests/auth/keyfile_rollover.js b/jstests/auth/keyfile_rollover.js index bbc704797ad..ea66397d8c8 100644 --- a/jstests/auth/keyfile_rollover.js +++ b/jstests/auth/keyfile_rollover.js @@ -11,82 +11,82 @@ TestData.skipGossipingClusterTime = true; (function() { - 'use strict'; +'use strict'; - let rst = new ReplSetTest({nodes: 3, keyFile: "jstests/libs/key1"}); - rst.startSet(); - rst.initiate(); +let rst = new ReplSetTest({nodes: 3, keyFile: "jstests/libs/key1"}); +rst.startSet(); +rst.initiate(); - const runPrimaryTest = function(fn) { - const curPrimary = rst.getPrimary(); - assert(curPrimary.getDB("admin").auth("root", "root")); - try { - fn(curPrimary); - rst.awaitSecondaryNodes(); - } finally { - curPrimary.getDB("admin").logout(); - } - }; +const runPrimaryTest = function(fn) { + const curPrimary = rst.getPrimary(); + assert(curPrimary.getDB("admin").auth("root", "root")); + try { + fn(curPrimary); + rst.awaitSecondaryNodes(); + } finally { + curPrimary.getDB("admin").logout(); + } +}; - // Create a user to login as when auth is enabled later - rst.getPrimary().getDB('admin').createUser({user: 'root', pwd: 'root', roles: ['root']}); - - runPrimaryTest((curPrimary) => { - assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); - assert.eq(1, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); - }); +// Create a user to login as when auth is enabled later +rst.getPrimary().getDB('admin').createUser({user: 'root', pwd: 'root', roles: ['root']}); - jsTestLog("Using keyForRollover to transition auth to both keys"); +runPrimaryTest((curPrimary) => { + assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); + assert.eq(1, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); +}); - /* - * This rolls over the cluster from one keyfile to another. The first argument is the keyfile - * servers should use, and the second is the keyfile the shell should use to authenticate - * with the servers. - */ - const rolloverKey = function(keyFileForServers, keyFileForAuth) { - // Update the keyFile parameter for the ReplSetTest as a whole - rst.keyFile = keyFileForServers; - // Function to restart a node with a new keyfile parameter and wait for secondaries - // to come back online - const restart = function(node) { - const nodeId = rst.getNodeId(node); - rst.stop(nodeId); - rst.start(nodeId, {keyFile: keyFileForServers}); - authutil.asCluster(rst.nodes, keyFileForAuth, () => { - rst.awaitSecondaryNodes(); - }); - }; +jsTestLog("Using keyForRollover to transition auth to both keys"); - // First we restart the secondaries. - rst.getSecondaries().forEach(function(secondary) { - restart(secondary); - }); - - // Then we restart the primary and wait for it to come back up with an ismaster call. - const primary = rst.getPrimary(); - restart(primary); - assert.soonNoExcept(() => { - authutil.asCluster(rst.nodes, keyFileForAuth, () => { - assert.commandWorked(primary.getDB("admin").runCommand({isMaster: 1})); - }); - return true; +/* + * This rolls over the cluster from one keyfile to another. The first argument is the keyfile + * servers should use, and the second is the keyfile the shell should use to authenticate + * with the servers. + */ +const rolloverKey = function(keyFileForServers, keyFileForAuth) { + // Update the keyFile parameter for the ReplSetTest as a whole + rst.keyFile = keyFileForServers; + // Function to restart a node with a new keyfile parameter and wait for secondaries + // to come back online + const restart = function(node) { + const nodeId = rst.getNodeId(node); + rst.stop(nodeId); + rst.start(nodeId, {keyFile: keyFileForServers}); + authutil.asCluster(rst.nodes, keyFileForAuth, () => { + rst.awaitSecondaryNodes(); }); }; - rolloverKey("jstests/libs/keyForRollover", "jstests/libs/key1"); + // First we restart the secondaries. + rst.getSecondaries().forEach(function(secondary) { + restart(secondary); + }); - runPrimaryTest((curPrimary) => { - assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); - assert.eq(2, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); + // Then we restart the primary and wait for it to come back up with an ismaster call. + const primary = rst.getPrimary(); + restart(primary); + assert.soonNoExcept(() => { + authutil.asCluster(rst.nodes, keyFileForAuth, () => { + assert.commandWorked(primary.getDB("admin").runCommand({isMaster: 1})); + }); + return true; }); +}; - jsTestLog("Upgrading set to use key2"); - rolloverKey("jstests/libs/key2", "jstests/libs/key2"); +rolloverKey("jstests/libs/keyForRollover", "jstests/libs/key1"); - runPrimaryTest((curPrimary) => { - assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); - assert.eq(3, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); - }); +runPrimaryTest((curPrimary) => { + assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); + assert.eq(2, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); +}); + +jsTestLog("Upgrading set to use key2"); +rolloverKey("jstests/libs/key2", "jstests/libs/key2"); + +runPrimaryTest((curPrimary) => { + assert.writeOK(curPrimary.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'})); + assert.eq(3, curPrimary.getDB('test').a.count(), 'Error interacting with replSet'); +}); - rst.stopSet(); +rst.stopSet(); })(); diff --git a/jstests/auth/kill_cursors.js b/jstests/auth/kill_cursors.js index dc49c7dba59..3d9a535311b 100644 --- a/jstests/auth/kill_cursors.js +++ b/jstests/auth/kill_cursors.js @@ -1,190 +1,174 @@ // Test the killCursors command. // @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(mongod) { - /** - * Open a cursor on `db` while authenticated as `authUsers`. - * Then logout, and log back in as `killUsers` and try to kill that cursor. - * - * @param db - The db to create a cursor on and ultimately kill agains. - * @param authUsers - Array of ['username', db] pairs to create the cursor under. - * @param killUsers - Array of ['username', dn] pairs to use when killing. - * @param shouldWork - Whether we expect success - */ - function tryKill(db, authUsers, killUsers, shouldWork) { - function loginAll(users) { - users.forEach(function(u) { - assert(u[1].auth(u[0], 'pass')); - }); - } +'use strict'; + +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + +function runTest(mongod) { + /** + * Open a cursor on `db` while authenticated as `authUsers`. + * Then logout, and log back in as `killUsers` and try to kill that cursor. + * + * @param db - The db to create a cursor on and ultimately kill agains. + * @param authUsers - Array of ['username', db] pairs to create the cursor under. + * @param killUsers - Array of ['username', dn] pairs to use when killing. + * @param shouldWork - Whether we expect success + */ + function tryKill(db, authUsers, killUsers, shouldWork) { + function loginAll(users) { + users.forEach(function(u) { + assert(u[1].auth(u[0], 'pass')); + }); + } - function logoutAll() { - [testA, testB].forEach(function(d) { - const users = assert.commandWorked(d.runCommand({connectionStatus: 1})) - .authInfo.authenticatedUsers; - users.forEach(function(u) { - mongod.getDB(u.db).logout(); - }); + function logoutAll() { + [testA, testB].forEach(function(d) { + const users = assert.commandWorked(d.runCommand({connectionStatus: 1})) + .authInfo.authenticatedUsers; + users.forEach(function(u) { + mongod.getDB(u.db).logout(); }); - } + }); + } - function doKill(extra) { - // Create a cursor to be killed later. - loginAll(authUsers); - let cmd = {find: db.coll.getName(), batchSize: 2}; - Object.assign(cmd, extra); - const id = assert.commandWorked(db.runCommand(cmd)).cursor.id; - assert.neq(id, 0, "Invalid cursor ID"); - logoutAll(); - - loginAll(killUsers); - const killCmd = db.runCommand({killCursors: db.coll.getName(), cursors: [id]}); - logoutAll(); - if (shouldWork) { - assert.commandWorked(killCmd, "Unable to kill cursor"); - } else { - assert.commandFailed(killCmd, "Should not have been able to kill cursor"); - } + function doKill(extra) { + // Create a cursor to be killed later. + loginAll(authUsers); + let cmd = {find: db.coll.getName(), batchSize: 2}; + Object.assign(cmd, extra); + const id = assert.commandWorked(db.runCommand(cmd)).cursor.id; + assert.neq(id, 0, "Invalid cursor ID"); + logoutAll(); + + loginAll(killUsers); + const killCmd = db.runCommand({killCursors: db.coll.getName(), cursors: [id]}); + logoutAll(); + if (shouldWork) { + assert.commandWorked(killCmd, "Unable to kill cursor"); + } else { + assert.commandFailed(killCmd, "Should not have been able to kill cursor"); } + } - doKill({}); + doKill({}); - if ((authUsers.length === 1) && (killUsers.length === 1)) { - // Session variant only makes sense with single auth'd users. - doKill({lsid: {id: BinData(4, "QlLfPHTySm6tqfuV+EOsVA==")}}); - } + if ((authUsers.length === 1) && (killUsers.length === 1)) { + // Session variant only makes sense with single auth'd users. + doKill({lsid: {id: BinData(4, "QlLfPHTySm6tqfuV+EOsVA==")}}); } + } - function trySelfKill(user) { - const db = user[1]; - assert(db.auth(user[0], 'pass')); - - assert.commandWorked(db.runCommand({startSession: 1})); + function trySelfKill(user) { + const db = user[1]; + assert(db.auth(user[0], 'pass')); - const cmd = { - aggregate: 1, - pipeline: [{$listLocalSessions: {}}], - cursor: {batchSize: 0} - }; - const res = assert.commandWorked(db.runCommand(cmd)); - print(tojson(res)); - const id = res.cursor.id; - assert.neq(id, 0, "Invalid cursor ID"); + assert.commandWorked(db.runCommand({startSession: 1})); - const killCmdRes = db.runCommand({killCursors: db.getName() + ".$cmd", cursors: [id]}); - db.logout(); + const cmd = {aggregate: 1, pipeline: [{$listLocalSessions: {}}], cursor: {batchSize: 0}}; + const res = assert.commandWorked(db.runCommand(cmd)); + print(tojson(res)); + const id = res.cursor.id; + assert.neq(id, 0, "Invalid cursor ID"); - assert.commandWorked(killCmdRes, "Unable to kill cursor"); - } + const killCmdRes = db.runCommand({killCursors: db.getName() + ".$cmd", cursors: [id]}); + db.logout(); - /** - * Create user1/user2 in testA, and user3/user4 in testB. - * Create two 101 element collections in testA and testB. - * Use various combinations of those users to open cursors, - * then (potentially) different combinations of users to kill them. - * - * A cursor should only be killable if at least one of the users - * who created it is trying to kill it. - */ - - const testA = mongod.getDB('testA'); - const testB = mongod.getDB('testB'); - const admin = mongod.getDB('admin'); - - // Setup users - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - - testA.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); - testA.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); - testB.createUser({user: 'user3', pwd: 'pass', roles: jsTest.basicUserRoles}); - testB.createUser({user: 'user4', pwd: 'pass', roles: jsTest.basicUserRoles}); - testB.createUser({user: 'user5', pwd: 'pass', roles: []}); - admin.logout(); - - // Create a collection with batchable data - assert(testA.auth('user1', 'pass')); - assert(testB.auth('user3', 'pass')); - for (var i = 0; i < 101; ++i) { - assert.writeOK(testA.coll.insert({_id: i})); - assert.writeOK(testB.coll.insert({_id: i})); - } - testA.logout(); - testB.logout(); - - // A user can kill their own cursor. - tryKill(testA, [['user1', testA]], [['user1', testA]], true); - tryKill(testA, [['user2', testA]], [['user2', testA]], true); - tryKill(testB, [['user3', testB]], [['user3', testB]], true); - tryKill(testB, [['user4', testB]], [['user4', testB]], true); - trySelfKill(['user1', testA]); - trySelfKill(['user5', testB]); - trySelfKill(['admin', admin]); - - // A user cannot kill someone else's cursor. - tryKill(testA, [['user1', testA]], [['user2', testA]], false); - tryKill(testA, [['user1', testA]], [['user2', testA], ['user3', testB]], false); - tryKill(testA, [['user2', testA]], [['user1', testA]], false); - tryKill(testA, [['user2', testA]], [['user1', testA], ['user3', testB]], false); - tryKill(testB, [['user3', testB]], [['user1', testA], ['user4', testB]], false); - tryKill(testB, [['user3', testB]], [['user2', testA], ['user4', testB]], false); - - // A multi-owned cursor can be killed by any/all owner. - tryKill(testA, [['user1', testA], ['user3', testB]], [['user1', testA]], true); - tryKill(testB, [['user1', testA], ['user3', testB]], [['user3', testB]], true); - tryKill(testA, - [['user1', testA], ['user3', testB]], - [['user1', testA], ['user3', testB]], - true); - tryKill(testA, - [['user1', testA], ['user3', testB]], - [['user2', testA], ['user3', testB]], - true); - tryKill(testB, - [['user1', testA], ['user3', testB]], - [['user1', testA], ['user3', testB]], - true); - tryKill(testB, - [['user1', testA], ['user3', testB]], - [['user1', testA], ['user4', testB]], - true); - - // An owned cursor can not be killed by other user(s). - tryKill(testA, - [['user1', testA], ['user3', testB]], - [['user2', testA], ['user4', testB]], - false); - tryKill(testA, [['user1', testA]], [['user2', testA], ['user3', testB]], false); - tryKill(testA, - [['user1', testA], ['user3', testB]], - [['user2', testA], ['user4', testB]], - false); - - // Admin can kill anything. - tryKill(testA, [['user1', testA]], [['admin', admin]], true); - tryKill(testA, [['user2', testA]], [['admin', admin]], true); - tryKill(testB, [['user3', testB]], [['admin', admin]], true); - tryKill(testB, [['user4', testB]], [['admin', admin]], true); - tryKill(testA, [['user1', testA], ['user3', testB]], [['admin', admin]], true); - tryKill(testB, [['user2', testA], ['user4', testB]], [['admin', admin]], true); + assert.commandWorked(killCmdRes, "Unable to kill cursor"); } - const mongod = MongoRunner.runMongod({auth: ""}); - runTest(mongod); - MongoRunner.stopMongod(mongod); - - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runTest(st.s0); - st.stop(); + /** + * Create user1/user2 in testA, and user3/user4 in testB. + * Create two 101 element collections in testA and testB. + * Use various combinations of those users to open cursors, + * then (potentially) different combinations of users to kill them. + * + * A cursor should only be killable if at least one of the users + * who created it is trying to kill it. + */ + + const testA = mongod.getDB('testA'); + const testB = mongod.getDB('testB'); + const admin = mongod.getDB('admin'); + + // Setup users + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + + testA.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); + testA.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); + testB.createUser({user: 'user3', pwd: 'pass', roles: jsTest.basicUserRoles}); + testB.createUser({user: 'user4', pwd: 'pass', roles: jsTest.basicUserRoles}); + testB.createUser({user: 'user5', pwd: 'pass', roles: []}); + admin.logout(); + + // Create a collection with batchable data + assert(testA.auth('user1', 'pass')); + assert(testB.auth('user3', 'pass')); + for (var i = 0; i < 101; ++i) { + assert.writeOK(testA.coll.insert({_id: i})); + assert.writeOK(testB.coll.insert({_id: i})); + } + testA.logout(); + testB.logout(); + + // A user can kill their own cursor. + tryKill(testA, [['user1', testA]], [['user1', testA]], true); + tryKill(testA, [['user2', testA]], [['user2', testA]], true); + tryKill(testB, [['user3', testB]], [['user3', testB]], true); + tryKill(testB, [['user4', testB]], [['user4', testB]], true); + trySelfKill(['user1', testA]); + trySelfKill(['user5', testB]); + trySelfKill(['admin', admin]); + + // A user cannot kill someone else's cursor. + tryKill(testA, [['user1', testA]], [['user2', testA]], false); + tryKill(testA, [['user1', testA]], [['user2', testA], ['user3', testB]], false); + tryKill(testA, [['user2', testA]], [['user1', testA]], false); + tryKill(testA, [['user2', testA]], [['user1', testA], ['user3', testB]], false); + tryKill(testB, [['user3', testB]], [['user1', testA], ['user4', testB]], false); + tryKill(testB, [['user3', testB]], [['user2', testA], ['user4', testB]], false); + + // A multi-owned cursor can be killed by any/all owner. + tryKill(testA, [['user1', testA], ['user3', testB]], [['user1', testA]], true); + tryKill(testB, [['user1', testA], ['user3', testB]], [['user3', testB]], true); + tryKill( + testA, [['user1', testA], ['user3', testB]], [['user1', testA], ['user3', testB]], true); + tryKill( + testA, [['user1', testA], ['user3', testB]], [['user2', testA], ['user3', testB]], true); + tryKill( + testB, [['user1', testA], ['user3', testB]], [['user1', testA], ['user3', testB]], true); + tryKill( + testB, [['user1', testA], ['user3', testB]], [['user1', testA], ['user4', testB]], true); + + // An owned cursor can not be killed by other user(s). + tryKill( + testA, [['user1', testA], ['user3', testB]], [['user2', testA], ['user4', testB]], false); + tryKill(testA, [['user1', testA]], [['user2', testA], ['user3', testB]], false); + tryKill( + testA, [['user1', testA], ['user3', testB]], [['user2', testA], ['user4', testB]], false); + + // Admin can kill anything. + tryKill(testA, [['user1', testA]], [['admin', admin]], true); + tryKill(testA, [['user2', testA]], [['admin', admin]], true); + tryKill(testB, [['user3', testB]], [['admin', admin]], true); + tryKill(testB, [['user4', testB]], [['admin', admin]], true); + tryKill(testA, [['user1', testA], ['user3', testB]], [['admin', admin]], true); + tryKill(testB, [['user2', testA], ['user4', testB]], [['admin', admin]], true); +} + +const mongod = MongoRunner.runMongod({auth: ""}); +runTest(mongod); +MongoRunner.stopMongod(mongod); + +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/kill_sessions.js b/jstests/auth/kill_sessions.js index f32a69ae2e8..99ddc51296f 100644 --- a/jstests/auth/kill_sessions.js +++ b/jstests/auth/kill_sessions.js @@ -1,17 +1,17 @@ load("jstests/libs/kill_sessions.js"); (function() { - 'use strict'; +'use strict'; - // TODO SERVER-35447: This test involves killing all sessions, which will not work as expected - // if the kill command is sent with an implicit session. - TestData.disableImplicitSessions = true; +// TODO SERVER-35447: This test involves killing all sessions, which will not work as expected +// if the kill command is sent with an implicit session. +TestData.disableImplicitSessions = true; - var forExec = MongoRunner.runMongod({auth: ""}); - var forKill = new Mongo(forExec.host); - var forVerify = new Mongo(forExec.host); - KillSessionsTestHelper.initializeAuth(forExec); - forVerify.getDB("admin").auth("super", "password"); - KillSessionsTestHelper.runAuth(forExec, forKill, [forVerify]); - MongoRunner.stopMongod(forExec); +var forExec = MongoRunner.runMongod({auth: ""}); +var forKill = new Mongo(forExec.host); +var forVerify = new Mongo(forExec.host); +KillSessionsTestHelper.initializeAuth(forExec); +forVerify.getDB("admin").auth("super", "password"); +KillSessionsTestHelper.runAuth(forExec, forKill, [forVerify]); +MongoRunner.stopMongod(forExec); })(); diff --git a/jstests/auth/killop_own_ops.js b/jstests/auth/killop_own_ops.js index 37498b53586..dbb1689708c 100644 --- a/jstests/auth/killop_own_ops.js +++ b/jstests/auth/killop_own_ops.js @@ -8,153 +8,148 @@ */ (function() { - 'use strict'; - - load("jstests/libs/fixture_helpers.js"); // For isMongos. - - function runTest(m, failPointName) { - var db = m.getDB("foo"); - var admin = m.getDB("admin"); - - admin.createUser({user: 'admin', pwd: 'password', roles: jsTest.adminUserRoles}); - admin.auth('admin', 'password'); - db.createUser({user: 'reader', pwd: 'reader', roles: [{db: 'foo', role: 'read'}]}); - db.createUser( - {user: 'otherReader', pwd: 'otherReader', roles: [{db: 'foo', role: 'read'}]}); - admin.createRole({ - role: 'opAdmin', - roles: [], - privileges: [{resource: {cluster: true}, actions: ['inprog', 'killop']}] - }); - db.createUser({user: 'opAdmin', pwd: 'opAdmin', roles: [{role: 'opAdmin', db: 'admin'}]}); - - var t = db.jstests_killop; - t.save({x: 1}); - - if (!FixtureHelpers.isMongos(db)) { - assert.commandWorked( - db.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1})); - } +'use strict'; - admin.logout(); +load("jstests/libs/fixture_helpers.js"); // For isMongos. - // Only used for nice error messages. - function getAllLocalOps() { - admin.aggregate([{$currentOp: {allUsers: true, localOps: true}}]).toArray(); - } +function runTest(m, failPointName) { + var db = m.getDB("foo"); + var admin = m.getDB("admin"); - /** - * This function filters for the operations that we're looking for, based on their state and - * the contents of their query object. - */ - function ops(ownOps = true) { - const ops = - admin.aggregate([{$currentOp: {allUsers: !ownOps, localOps: true}}]).toArray(); - - var ids = []; - for (let o of ops) { - if ((o.active || o.waitingForLock) && o.command && - o.command.find === "jstests_killop" && o.command.comment === "kill_own_ops") { - ids.push(o.opid); - } - } - return ids; - } + admin.createUser({user: 'admin', pwd: 'password', roles: jsTest.adminUserRoles}); + admin.auth('admin', 'password'); + db.createUser({user: 'reader', pwd: 'reader', roles: [{db: 'foo', role: 'read'}]}); + db.createUser({user: 'otherReader', pwd: 'otherReader', roles: [{db: 'foo', role: 'read'}]}); + admin.createRole({ + role: 'opAdmin', + roles: [], + privileges: [{resource: {cluster: true}, actions: ['inprog', 'killop']}] + }); + db.createUser({user: 'opAdmin', pwd: 'opAdmin', roles: [{role: 'opAdmin', db: 'admin'}]}); - var queryAsReader = - 'db = db.getSiblingDB("foo"); db.auth("reader", "reader"); db.jstests_killop.find().comment("kill_own_ops").toArray()'; + var t = db.jstests_killop; + t.save({x: 1}); - jsTestLog("Starting long-running operation"); - db.auth('reader', 'reader'); - assert.commandWorked( - db.adminCommand({configureFailPoint: failPointName, mode: "alwaysOn"})); - var s1 = startParallelShell(queryAsReader, m.port); - jsTestLog("Finding ops in $currentOp output"); - var o = []; - assert.soon( - function() { - o = ops(); - return o.length == 1; - }, - () => { - return tojson(getAllLocalOps()); - }, - 60000); - jsTestLog("Checking that another user cannot see or kill the op"); - db.logout(); - db.auth('otherReader', 'otherReader'); - assert.eq([], ops()); - assert.commandFailed(db.killOp(o[0])); - db.logout(); - db.auth('reader', 'reader'); - assert.eq(1, ops().length); - db.logout(); - jsTestLog("Checking that originating user can kill operation"); - var start = new Date(); - db.auth('reader', 'reader'); - assert.commandWorked(db.killOp(o[0])); - assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "off"})); - - jsTestLog("Waiting for ops to terminate"); - var exitCode = s1({checkExitSuccess: false}); - assert.neq(0, - exitCode, - "expected shell to exit abnormally due to operation execution being terminated"); - - // don't want to pass if timeout killed the js function. - var end = new Date(); - var diff = end - start; - assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff); - - jsTestLog("Starting a second long-running operation"); + if (!FixtureHelpers.isMongos(db)) { assert.commandWorked( - db.adminCommand({configureFailPoint: failPointName, mode: "alwaysOn"})); - var s2 = startParallelShell(queryAsReader, m.port); - jsTestLog("Finding ops in $currentOp output"); - var o2 = []; - assert.soon( - function() { - o2 = ops(); - return o2.length == 1; - }, - () => { - return tojson(getAllLocalOps()); - }, - 60000); - - db.logout(); - db.auth('opAdmin', 'opAdmin'); - - jsTestLog("Checking that an administrative user can find others' operations"); - assert.eq(o2, ops(false)); - - jsTestLog( - "Checking that an administrative user cannot find others' operations with ownOps"); - assert.eq([], ops()); - - jsTestLog("Checking that an administrative user can kill others' operations"); - var start = new Date(); - assert.commandWorked(db.killOp(o2[0])); - assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "off"})); - jsTestLog("Waiting for ops to terminate"); - var exitCode = s2({checkExitSuccess: false}); - assert.neq( - 0, exitCode, "expected shell to exit abnormally due to JS execution being terminated"); - - var end = new Date(); - var diff = end - start; - assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff); + db.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1})); + } + + admin.logout(); + + // Only used for nice error messages. + function getAllLocalOps() { + admin.aggregate([{$currentOp: {allUsers: true, localOps: true}}]).toArray(); + } + + /** + * This function filters for the operations that we're looking for, based on their state and + * the contents of their query object. + */ + function ops(ownOps = true) { + const ops = admin.aggregate([{$currentOp: {allUsers: !ownOps, localOps: true}}]).toArray(); + + var ids = []; + for (let o of ops) { + if ((o.active || o.waitingForLock) && o.command && + o.command.find === "jstests_killop" && o.command.comment === "kill_own_ops") { + ids.push(o.opid); + } + } + return ids; } - var conn = MongoRunner.runMongod({auth: ""}); - runTest(conn, "setYieldAllLocksHang"); - MongoRunner.stopMongod(conn); - - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest( - {shards: 1, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); - // Use a different failpoint in the sharded version, since the mongos does not have a - // setYieldAlllocksHang failpoint. - runTest(st.s, "waitInFindBeforeMakingBatch"); - st.stop(); + var queryAsReader = + 'db = db.getSiblingDB("foo"); db.auth("reader", "reader"); db.jstests_killop.find().comment("kill_own_ops").toArray()'; + + jsTestLog("Starting long-running operation"); + db.auth('reader', 'reader'); + assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "alwaysOn"})); + var s1 = startParallelShell(queryAsReader, m.port); + jsTestLog("Finding ops in $currentOp output"); + var o = []; + assert.soon( + function() { + o = ops(); + return o.length == 1; + }, + () => { + return tojson(getAllLocalOps()); + }, + 60000); + jsTestLog("Checking that another user cannot see or kill the op"); + db.logout(); + db.auth('otherReader', 'otherReader'); + assert.eq([], ops()); + assert.commandFailed(db.killOp(o[0])); + db.logout(); + db.auth('reader', 'reader'); + assert.eq(1, ops().length); + db.logout(); + jsTestLog("Checking that originating user can kill operation"); + var start = new Date(); + db.auth('reader', 'reader'); + assert.commandWorked(db.killOp(o[0])); + assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "off"})); + + jsTestLog("Waiting for ops to terminate"); + var exitCode = s1({checkExitSuccess: false}); + assert.neq(0, + exitCode, + "expected shell to exit abnormally due to operation execution being terminated"); + + // don't want to pass if timeout killed the js function. + var end = new Date(); + var diff = end - start; + assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff); + + jsTestLog("Starting a second long-running operation"); + assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "alwaysOn"})); + var s2 = startParallelShell(queryAsReader, m.port); + jsTestLog("Finding ops in $currentOp output"); + var o2 = []; + assert.soon( + function() { + o2 = ops(); + return o2.length == 1; + }, + () => { + return tojson(getAllLocalOps()); + }, + 60000); + + db.logout(); + db.auth('opAdmin', 'opAdmin'); + + jsTestLog("Checking that an administrative user can find others' operations"); + assert.eq(o2, ops(false)); + + jsTestLog("Checking that an administrative user cannot find others' operations with ownOps"); + assert.eq([], ops()); + + jsTestLog("Checking that an administrative user can kill others' operations"); + var start = new Date(); + assert.commandWorked(db.killOp(o2[0])); + assert.commandWorked(db.adminCommand({configureFailPoint: failPointName, mode: "off"})); + jsTestLog("Waiting for ops to terminate"); + var exitCode = s2({checkExitSuccess: false}); + assert.neq( + 0, exitCode, "expected shell to exit abnormally due to JS execution being terminated"); + + var end = new Date(); + var diff = end - start; + assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff); +} + +var conn = MongoRunner.runMongod({auth: ""}); +runTest(conn, "setYieldAllLocksHang"); +MongoRunner.stopMongod(conn); + +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = + new ShardingTest({shards: 1, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); +// Use a different failpoint in the sharded version, since the mongos does not have a +// setYieldAlllocksHang failpoint. +runTest(st.s, "waitInFindBeforeMakingBatch"); +st.stop(); })(); diff --git a/jstests/auth/list_all_local_sessions.js b/jstests/auth/list_all_local_sessions.js index 3b7c19d1cbe..92363515a00 100644 --- a/jstests/auth/list_all_local_sessions.js +++ b/jstests/auth/list_all_local_sessions.js @@ -2,60 +2,60 @@ // @tags: [requires_sharding] (function() { - 'use strict'; - load('jstests/aggregation/extras/utils.js'); - - // This test makes assertions about the number of sessions, which are not compatible with - // implicit sessions. - TestData.disableImplicitSessions = true; - - function runListAllLocalSessionsTest(mongod) { - assert(mongod); - const admin = mongod.getDB("admin"); - const db = mongod.getDB("test"); - - const pipeline = [{'$listLocalSessions': {allUsers: true}}]; - function listAllLocalSessions() { - return admin.aggregate(pipeline); - } - - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - db.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.logout(); - - // Shouldn't be able to listLocalSessions when not logged in. - assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); - - // Start a new session and capture its sessionId. - assert(db.auth('user1', 'pass')); - const myid = assert.commandWorked(db.runCommand({startSession: 1})).id.id; - assert(myid !== undefined); - - // Ensure that a normal user can NOT listAllLocalSessions to view their session. - assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); - db.logout(); - - // Ensure that the cache now contains the session and is visible by admin. - assert(admin.auth('admin', 'pass')); - const resultArray = assert.doesNotThrow(listAllLocalSessions).toArray(); - assert.eq(resultArray.length, 1); - const cacheid = resultArray[0]._id.id; - assert(cacheid !== undefined); - assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); +'use strict'; +load('jstests/aggregation/extras/utils.js'); + +// This test makes assertions about the number of sessions, which are not compatible with +// implicit sessions. +TestData.disableImplicitSessions = true; + +function runListAllLocalSessionsTest(mongod) { + assert(mongod); + const admin = mongod.getDB("admin"); + const db = mongod.getDB("test"); + + const pipeline = [{'$listLocalSessions': {allUsers: true}}]; + function listAllLocalSessions() { + return admin.aggregate(pipeline); } - const mongod = MongoRunner.runMongod({auth: ""}); - runListAllLocalSessionsTest(mongod); - MongoRunner.stopMongod(mongod); - - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runListAllLocalSessionsTest(st.s0); - st.stop(); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + db.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); + admin.logout(); + + // Shouldn't be able to listLocalSessions when not logged in. + assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); + + // Start a new session and capture its sessionId. + assert(db.auth('user1', 'pass')); + const myid = assert.commandWorked(db.runCommand({startSession: 1})).id.id; + assert(myid !== undefined); + + // Ensure that a normal user can NOT listAllLocalSessions to view their session. + assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); + db.logout(); + + // Ensure that the cache now contains the session and is visible by admin. + assert(admin.auth('admin', 'pass')); + const resultArray = assert.doesNotThrow(listAllLocalSessions).toArray(); + assert.eq(resultArray.length, 1); + const cacheid = resultArray[0]._id.id; + assert(cacheid !== undefined); + assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); +} + +const mongod = MongoRunner.runMongod({auth: ""}); +runListAllLocalSessionsTest(mongod); +MongoRunner.stopMongod(mongod); + +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runListAllLocalSessionsTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/list_all_sessions.js b/jstests/auth/list_all_sessions.js index 7f077bee537..9ba823564a7 100644 --- a/jstests/auth/list_all_sessions.js +++ b/jstests/auth/list_all_sessions.js @@ -2,67 +2,67 @@ // @tags: [requires_sharding] (function() { - 'use strict'; - load('jstests/aggregation/extras/utils.js'); +'use strict'; +load('jstests/aggregation/extras/utils.js'); - // This test makes assertions about the number of sessions, which are not compatible with - // implicit sessions. - TestData.disableImplicitSessions = true; +// This test makes assertions about the number of sessions, which are not compatible with +// implicit sessions. +TestData.disableImplicitSessions = true; - function runListAllSessionsTest(mongod) { - assert(mongod); - const admin = mongod.getDB("admin"); - const config = mongod.getDB("config"); +function runListAllSessionsTest(mongod) { + assert(mongod); + const admin = mongod.getDB("admin"); + const config = mongod.getDB("config"); - const pipeline = [{'$listSessions': {allUsers: true}}]; - function listSessions() { - return config.system.sessions.aggregate(pipeline); - } + const pipeline = [{'$listSessions': {allUsers: true}}]; + function listSessions() { + return config.system.sessions.aggregate(pipeline); + } - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - admin.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.logout(); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + admin.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); + admin.logout(); - // Fail if we're not logged in. - assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); + // Fail if we're not logged in. + assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); - // Start a new session and capture its sessionId. - assert(admin.auth('user1', 'pass')); - const myid = assert.commandWorked(admin.runCommand({startSession: 1})).id.id; - assert(myid !== undefined); - assert.commandWorked(admin.runCommand({refreshLogicalSessionCacheNow: 1})); + // Start a new session and capture its sessionId. + assert(admin.auth('user1', 'pass')); + const myid = assert.commandWorked(admin.runCommand({startSession: 1})).id.id; + assert(myid !== undefined); + assert.commandWorked(admin.runCommand({refreshLogicalSessionCacheNow: 1})); - // Ensure that a normal user can NOT listSessions{allUsers:true} to view their session. - assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); + // Ensure that a normal user can NOT listSessions{allUsers:true} to view their session. + assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); - // Ensure that a normal user can NOT listSessions to view others' sessions. - const viewAdminPipeline = [{'$listSessions': {users: [{user: 'admin', db: 'admin'}]}}]; - assertErrorCode(config.system.sessions, viewAdminPipeline, ErrorCodes.Unauthorized); + // Ensure that a normal user can NOT listSessions to view others' sessions. + const viewAdminPipeline = [{'$listSessions': {users: [{user: 'admin', db: 'admin'}]}}]; + assertErrorCode(config.system.sessions, viewAdminPipeline, ErrorCodes.Unauthorized); - // Ensure that the cache now contains the session and is visible by admin - assert(admin.auth('admin', 'pass')); - const resultArray = listSessions().toArray(); - assert.eq(resultArray.length, 1); - const cacheid = resultArray[0]._id.id; - assert(cacheid !== undefined); - assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); + // Ensure that the cache now contains the session and is visible by admin + assert(admin.auth('admin', 'pass')); + const resultArray = listSessions().toArray(); + assert.eq(resultArray.length, 1); + const cacheid = resultArray[0]._id.id; + assert(cacheid !== undefined); + assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); - // Make sure pipelining other collections fail. - assertErrorCode(admin.system.collections, pipeline, ErrorCodes.InvalidNamespace); - } + // Make sure pipelining other collections fail. + assertErrorCode(admin.system.collections, pipeline, ErrorCodes.InvalidNamespace); +} - const mongod = MongoRunner.runMongod({auth: ""}); - runListAllSessionsTest(mongod); - MongoRunner.stopMongod(mongod); +const mongod = MongoRunner.runMongod({auth: ""}); +runListAllSessionsTest(mongod); +MongoRunner.stopMongod(mongod); - const st = - new ShardingTest({shards: 1, mongos: 1, config: 1, other: {keyFile: 'jstests/libs/key1'}}); +const st = + new ShardingTest({shards: 1, mongos: 1, config: 1, other: {keyFile: 'jstests/libs/key1'}}); - // Ensure that the sessions collection exists. - st.c0.getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1}); - st.rs0.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1}); +// Ensure that the sessions collection exists. +st.c0.getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1}); +st.rs0.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1}); - runListAllSessionsTest(st.s0); - st.stop(); +runListAllSessionsTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/list_collections_filter_views.js b/jstests/auth/list_collections_filter_views.js index d17c9d82101..eeb12c74051 100644 --- a/jstests/auth/list_collections_filter_views.js +++ b/jstests/auth/list_collections_filter_views.js @@ -1,58 +1,57 @@ // Test listCollections with unauthorized views. (function() { - "use strict"; - - const dbName = "list_collections_filter_views"; - - function runTestOnConnection(conn) { - const admin = conn.getDB("admin"); - const db = conn.getDB("test"); - - assert.commandWorked(admin.runCommand({createUser: "root", pwd: "root", roles: ["root"]})); - assert(admin.auth("root", "root")); - - assert.commandWorked(db.foo.insert({x: 123})); - assert.commandWorked(db.createView("bar", "foo", [])); - assert.commandWorked(db.createView("baz", "foo", [])); - - assert.commandWorked(db.runCommand({ - createRole: "role", - roles: [], - privileges: [ - {resource: {db: "test", collection: "foo"}, actions: ["find"]}, - {resource: {db: "test", collection: "bar"}, actions: ["find"]} - ] - })); - - assert.commandWorked( - db.runCommand({createUser: "user", pwd: "pwd", roles: [{role: "role", db: "test"}]})); - admin.logout(); - - assert(db.auth("user", "pwd")); - - const res = assert.commandWorked( - db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true})); - assert.eq(2, res.cursor.firstBatch.length, tojson(res.cursor.firstBatch)); - - function nameSort(a, b) { - return a.name > b.name; - } - assert.eq( - [{"name": "bar", "type": "view"}, {"name": "foo", "type": "collection"}].sort(nameSort), - res.cursor.firstBatch.sort(nameSort)); - } +"use strict"; + +const dbName = "list_collections_filter_views"; + +function runTestOnConnection(conn) { + const admin = conn.getDB("admin"); + const db = conn.getDB("test"); + + assert.commandWorked(admin.runCommand({createUser: "root", pwd: "root", roles: ["root"]})); + assert(admin.auth("root", "root")); - const mongod = MongoRunner.runMongod({auth: ''}); - runTestOnConnection(mongod); - MongoRunner.stopMongod(mongod); + assert.commandWorked(db.foo.insert({x: 123})); + assert.commandWorked(db.createView("bar", "foo", [])); + assert.commandWorked(db.createView("baz", "foo", [])); - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false}, - }); - runTestOnConnection(st.s0); - st.stop(); + assert.commandWorked(db.runCommand({ + createRole: "role", + roles: [], + privileges: [ + {resource: {db: "test", collection: "foo"}, actions: ["find"]}, + {resource: {db: "test", collection: "bar"}, actions: ["find"]} + ] + })); + assert.commandWorked( + db.runCommand({createUser: "user", pwd: "pwd", roles: [{role: "role", db: "test"}]})); + admin.logout(); + + assert(db.auth("user", "pwd")); + + const res = assert.commandWorked( + db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true})); + assert.eq(2, res.cursor.firstBatch.length, tojson(res.cursor.firstBatch)); + + function nameSort(a, b) { + return a.name > b.name; + } + assert.eq( + [{"name": "bar", "type": "view"}, {"name": "foo", "type": "collection"}].sort(nameSort), + res.cursor.firstBatch.sort(nameSort)); +} + +const mongod = MongoRunner.runMongod({auth: ''}); +runTestOnConnection(mongod); +MongoRunner.stopMongod(mongod); + +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false}, +}); +runTestOnConnection(st.s0); +st.stop(); }()); diff --git a/jstests/auth/list_collections_own_collections.js b/jstests/auth/list_collections_own_collections.js index 82d17afc787..08acf45ab02 100644 --- a/jstests/auth/list_collections_own_collections.js +++ b/jstests/auth/list_collections_own_collections.js @@ -1,183 +1,186 @@ // Test nameOnly option of listCollections (function() { - "use strict"; - - const dbName = "list_collections_own_collections"; - - const nameSort = (a, b) => a.name > b.name; - const resFoo = {"name": "foo", "type": "collection"}; - const resBar = {"name": "bar", "type": "view"}; - const resOther = - [{"name": "otherCollection", "type": "collection"}, {"name": "otherView", "type": "view"}]; - const resSystemViews = {"name": "system.views", "type": "collection"}; - - function runTestOnConnection(conn) { - const admin = conn.getDB("admin"); - const db = conn.getDB(dbName); - - assert.commandWorked(admin.runCommand({createUser: "root", pwd: "root", roles: ["root"]})); - assert(admin.auth("root", "root")); - - function createTestRoleAndUser(roleName, privs) { - assert.commandWorked( - admin.runCommand({createRole: roleName, roles: [], privileges: privs})); - - const userName = "user|" + roleName; - assert.commandWorked(db.runCommand( - {createUser: userName, pwd: "pwd", roles: [{role: roleName, db: "admin"}]})); - } - - createTestRoleAndUser("roleWithExactNamespacePrivileges", [ - {resource: {db: dbName, collection: "foo"}, actions: ["find"]}, - {resource: {db: dbName, collection: "bar"}, actions: ["find"]} - ]); - - createTestRoleAndUser("roleWithExactNamespaceAndSystemPrivileges", [ - {resource: {db: dbName, collection: "foo"}, actions: ["find"]}, - {resource: {db: dbName, collection: "bar"}, actions: ["find"]}, - {resource: {db: dbName, collection: "system.views"}, actions: ["find"]} - ]); - - createTestRoleAndUser("roleWithCollectionPrivileges", [ - {resource: {db: "", collection: "foo"}, actions: ["find"]}, - {resource: {db: "", collection: "bar"}, actions: ["find"]} - ]); - - createTestRoleAndUser("roleWithCollectionAndSystemPrivileges", [ - {resource: {db: "", collection: "foo"}, actions: ["find"]}, - {resource: {db: "", collection: "bar"}, actions: ["find"]}, - {resource: {db: "", collection: "system.views"}, actions: ["find"]} - ]); - - createTestRoleAndUser("roleWithDatabasePrivileges", [ - {resource: {db: dbName, collection: ""}, actions: ["find"]}, - ]); - - createTestRoleAndUser("roleWithDatabaseAndSystemPrivileges", [ - {resource: {db: dbName, collection: ""}, actions: ["find"]}, - {resource: {db: dbName, collection: "system.views"}, actions: ["find"]} - ]); - - createTestRoleAndUser("roleWithAnyNormalResourcePrivileges", [ - {resource: {db: "", collection: ""}, actions: ["find"]}, - ]); - - createTestRoleAndUser("roleWithAnyNormalResourceAndSystemPrivileges", [ - {resource: {db: "", collection: ""}, actions: ["find"]}, - {resource: {db: "", collection: "system.views"}, actions: ["find"]} - ]); - - // Create the collection and view used by the tests. - assert.commandWorked(db.dropDatabase()); - assert.commandWorked(db.createCollection("foo")); - assert.commandWorked(db.createView("bar", "foo", [])); - - // Create a collection and view that are never granted specific permissions, to ensure - // they're only returned by listCollections when the role has access to the whole db/server. - assert.commandWorked(db.createCollection("otherCollection")); - assert.commandWorked(db.createView("otherView", "otherCollection", [])); - - admin.logout(); - - function runTestOnRole(roleName, expectedColls) { - jsTestLog(roleName); - const userName = "user|" + roleName; - assert(db.auth(userName, "pwd")); - - let res; - - res = db.runCommand({listCollections: 1}); - assert.commandFailed(res); - res = db.runCommand({listCollections: 1, nameOnly: true}); - assert.commandFailed(res); - res = db.runCommand({listCollections: 1, authorizedCollections: true}); - assert.commandFailed(res); - - res = db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true}); - assert.commandWorked(res); - assert.eq(expectedColls.sort(nameSort), res.cursor.firstBatch.sort(nameSort)); - - res = db.runCommand({ - listCollections: 1, - nameOnly: true, - authorizedCollections: true, - filter: {"name": "foo"} - }); - assert.commandWorked(res); - assert.eq([resFoo], res.cursor.firstBatch); - - db.logout(); - } - - runTestOnRole("roleWithExactNamespacePrivileges", [resFoo, resBar]); - runTestOnRole("roleWithExactNamespaceAndSystemPrivileges", - [resFoo, resBar, resSystemViews]); - - runTestOnRole("roleWithCollectionPrivileges", [resFoo, resBar]); - runTestOnRole("roleWithCollectionAndSystemPrivileges", [resFoo, resBar, resSystemViews]); - - runTestOnRole("roleWithDatabasePrivileges", [resFoo, resBar, ...resOther]); - runTestOnRole("roleWithDatabaseAndSystemPrivileges", - [resFoo, resBar, ...resOther, resSystemViews]); - - runTestOnRole("roleWithAnyNormalResourcePrivileges", [resFoo, resBar, ...resOther]); - runTestOnRole("roleWithAnyNormalResourceAndSystemPrivileges", - [resFoo, resBar, ...resOther, resSystemViews]); +"use strict"; + +const dbName = "list_collections_own_collections"; + +const nameSort = (a, b) => a.name > b.name; +const resFoo = { + "name": "foo", + "type": "collection" +}; +const resBar = { + "name": "bar", + "type": "view" +}; +const resOther = + [{"name": "otherCollection", "type": "collection"}, {"name": "otherView", "type": "view"}]; +const resSystemViews = { + "name": "system.views", + "type": "collection" +}; + +function runTestOnConnection(conn) { + const admin = conn.getDB("admin"); + const db = conn.getDB(dbName); + + assert.commandWorked(admin.runCommand({createUser: "root", pwd: "root", roles: ["root"]})); + assert(admin.auth("root", "root")); + + function createTestRoleAndUser(roleName, privs) { + assert.commandWorked( + admin.runCommand({createRole: roleName, roles: [], privileges: privs})); + + const userName = "user|" + roleName; + assert.commandWorked(db.runCommand( + {createUser: userName, pwd: "pwd", roles: [{role: roleName, db: "admin"}]})); } - function runNoAuthTestOnConnection(conn) { - const admin = conn.getDB("admin"); - const db = conn.getDB(dbName); - - assert.commandWorked(db.dropDatabase()); - assert.commandWorked(db.createCollection("foo")); - assert.commandWorked(db.createView("bar", "foo", [])); - - var resFull = db.runCommand({listCollections: 1}); - assert.commandWorked(resFull); - var resAuthColls = db.runCommand({listCollections: 1, authorizedCollections: true}); - assert.commandWorked(resAuthColls); - assert.eq(resFull.cursor.firstBatch.sort(nameSort), - resAuthColls.cursor.firstBatch.sort(nameSort)); - - var resNameOnly = db.runCommand({listCollections: 1, nameOnly: true}); - assert.commandWorked(resNameOnly); - var resNameOnlyAuthColls = - db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true}); - assert.commandWorked(resNameOnlyAuthColls); - assert.eq(resNameOnly.cursor.firstBatch.sort(nameSort), - resNameOnlyAuthColls.cursor.firstBatch.sort(nameSort)); - - var resWithFilter = db.runCommand({ + createTestRoleAndUser("roleWithExactNamespacePrivileges", [ + {resource: {db: dbName, collection: "foo"}, actions: ["find"]}, + {resource: {db: dbName, collection: "bar"}, actions: ["find"]} + ]); + + createTestRoleAndUser("roleWithExactNamespaceAndSystemPrivileges", [ + {resource: {db: dbName, collection: "foo"}, actions: ["find"]}, + {resource: {db: dbName, collection: "bar"}, actions: ["find"]}, + {resource: {db: dbName, collection: "system.views"}, actions: ["find"]} + ]); + + createTestRoleAndUser("roleWithCollectionPrivileges", [ + {resource: {db: "", collection: "foo"}, actions: ["find"]}, + {resource: {db: "", collection: "bar"}, actions: ["find"]} + ]); + + createTestRoleAndUser("roleWithCollectionAndSystemPrivileges", [ + {resource: {db: "", collection: "foo"}, actions: ["find"]}, + {resource: {db: "", collection: "bar"}, actions: ["find"]}, + {resource: {db: "", collection: "system.views"}, actions: ["find"]} + ]); + + createTestRoleAndUser("roleWithDatabasePrivileges", [ + {resource: {db: dbName, collection: ""}, actions: ["find"]}, + ]); + + createTestRoleAndUser("roleWithDatabaseAndSystemPrivileges", [ + {resource: {db: dbName, collection: ""}, actions: ["find"]}, + {resource: {db: dbName, collection: "system.views"}, actions: ["find"]} + ]); + + createTestRoleAndUser("roleWithAnyNormalResourcePrivileges", [ + {resource: {db: "", collection: ""}, actions: ["find"]}, + ]); + + createTestRoleAndUser("roleWithAnyNormalResourceAndSystemPrivileges", [ + {resource: {db: "", collection: ""}, actions: ["find"]}, + {resource: {db: "", collection: "system.views"}, actions: ["find"]} + ]); + + // Create the collection and view used by the tests. + assert.commandWorked(db.dropDatabase()); + assert.commandWorked(db.createCollection("foo")); + assert.commandWorked(db.createView("bar", "foo", [])); + + // Create a collection and view that are never granted specific permissions, to ensure + // they're only returned by listCollections when the role has access to the whole db/server. + assert.commandWorked(db.createCollection("otherCollection")); + assert.commandWorked(db.createView("otherView", "otherCollection", [])); + + admin.logout(); + + function runTestOnRole(roleName, expectedColls) { + jsTestLog(roleName); + const userName = "user|" + roleName; + assert(db.auth(userName, "pwd")); + + let res; + + res = db.runCommand({listCollections: 1}); + assert.commandFailed(res); + res = db.runCommand({listCollections: 1, nameOnly: true}); + assert.commandFailed(res); + res = db.runCommand({listCollections: 1, authorizedCollections: true}); + assert.commandFailed(res); + + res = db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true}); + assert.commandWorked(res); + assert.eq(expectedColls.sort(nameSort), res.cursor.firstBatch.sort(nameSort)); + + res = db.runCommand({ listCollections: 1, nameOnly: true, authorizedCollections: true, filter: {"name": "foo"} }); - assert.commandWorked(resWithFilter); - assert.eq([{"name": "foo", "type": "collection"}], resWithFilter.cursor.firstBatch); - } - - const mongod = MongoRunner.runMongod({auth: ''}); - runTestOnConnection(mongod); - MongoRunner.stopMongod(mongod); - - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runTestOnConnection(st.s0); - st.stop(); + assert.commandWorked(res); + assert.eq([resFoo], res.cursor.firstBatch); - const mongodNoAuth = MongoRunner.runMongod(); - runNoAuthTestOnConnection(mongodNoAuth); - MongoRunner.stopMongod(mongodNoAuth); - - const stNoAuth = - new ShardingTest({shards: 1, mongos: 1, config: 1, other: {shardAsReplicaSet: false}}); - runNoAuthTestOnConnection(stNoAuth.s0); - stNoAuth.stop(); + db.logout(); + } + runTestOnRole("roleWithExactNamespacePrivileges", [resFoo, resBar]); + runTestOnRole("roleWithExactNamespaceAndSystemPrivileges", [resFoo, resBar, resSystemViews]); + + runTestOnRole("roleWithCollectionPrivileges", [resFoo, resBar]); + runTestOnRole("roleWithCollectionAndSystemPrivileges", [resFoo, resBar, resSystemViews]); + + runTestOnRole("roleWithDatabasePrivileges", [resFoo, resBar, ...resOther]); + runTestOnRole("roleWithDatabaseAndSystemPrivileges", + [resFoo, resBar, ...resOther, resSystemViews]); + + runTestOnRole("roleWithAnyNormalResourcePrivileges", [resFoo, resBar, ...resOther]); + runTestOnRole("roleWithAnyNormalResourceAndSystemPrivileges", + [resFoo, resBar, ...resOther, resSystemViews]); +} + +function runNoAuthTestOnConnection(conn) { + const admin = conn.getDB("admin"); + const db = conn.getDB(dbName); + + assert.commandWorked(db.dropDatabase()); + assert.commandWorked(db.createCollection("foo")); + assert.commandWorked(db.createView("bar", "foo", [])); + + var resFull = db.runCommand({listCollections: 1}); + assert.commandWorked(resFull); + var resAuthColls = db.runCommand({listCollections: 1, authorizedCollections: true}); + assert.commandWorked(resAuthColls); + assert.eq(resFull.cursor.firstBatch.sort(nameSort), + resAuthColls.cursor.firstBatch.sort(nameSort)); + + var resNameOnly = db.runCommand({listCollections: 1, nameOnly: true}); + assert.commandWorked(resNameOnly); + var resNameOnlyAuthColls = + db.runCommand({listCollections: 1, nameOnly: true, authorizedCollections: true}); + assert.commandWorked(resNameOnlyAuthColls); + assert.eq(resNameOnly.cursor.firstBatch.sort(nameSort), + resNameOnlyAuthColls.cursor.firstBatch.sort(nameSort)); + + var resWithFilter = db.runCommand( + {listCollections: 1, nameOnly: true, authorizedCollections: true, filter: {"name": "foo"}}); + assert.commandWorked(resWithFilter); + assert.eq([{"name": "foo", "type": "collection"}], resWithFilter.cursor.firstBatch); +} + +const mongod = MongoRunner.runMongod({auth: ''}); +runTestOnConnection(mongod); +MongoRunner.stopMongod(mongod); + +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runTestOnConnection(st.s0); +st.stop(); + +const mongodNoAuth = MongoRunner.runMongod(); +runNoAuthTestOnConnection(mongodNoAuth); +MongoRunner.stopMongod(mongodNoAuth); + +const stNoAuth = + new ShardingTest({shards: 1, mongos: 1, config: 1, other: {shardAsReplicaSet: false}}); +runNoAuthTestOnConnection(stNoAuth.s0); +stNoAuth.stop(); }()); diff --git a/jstests/auth/list_databases.js b/jstests/auth/list_databases.js index a69472fb77f..2e374e54fd6 100644 --- a/jstests/auth/list_databases.js +++ b/jstests/auth/list_databases.js @@ -1,167 +1,167 @@ // Auth tests for the listDatabases command. (function() { - 'use strict'; +'use strict'; - function runTest(mongod) { - const admin = mongod.getDB('admin'); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); +function runTest(mongod) { + const admin = mongod.getDB('admin'); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); - // Establish db0..db7 - for (let i = 0; i < 8; ++i) { - mongod.getDB('db' + i).foo.insert({bar: "baz"}); - } - mongod.getDB("db0").baz.insert({x: "y"}); - mongod.getDB("db2").baz.insert({x: "y"}); - - admin.createRole({ - role: 'dbLister', - privileges: [{resource: {cluster: true}, actions: ['listDatabases']}], - roles: [] - }); - - admin.createRole({ - role: 'specificCollection', - privileges: [{resource: {db: "db0", collection: "baz"}, actions: ['find']}], - roles: [] - }); - - admin.createRole({ - role: 'sharedNameCollections', - privileges: [{resource: {db: "", collection: "baz"}, actions: ['find']}], - roles: [] - }); - - // Make db0, db2, db4, db6 readable to user1 abd user3. - // Make db0, db1, db2, db3 read/writable to user 2 and user3. - function makeRole(perm, dbNum) { - return {role: perm, db: ("db" + dbNum)}; + // Establish db0..db7 + for (let i = 0; i < 8; ++i) { + mongod.getDB('db' + i).foo.insert({bar: "baz"}); + } + mongod.getDB("db0").baz.insert({x: "y"}); + mongod.getDB("db2").baz.insert({x: "y"}); + + admin.createRole({ + role: 'dbLister', + privileges: [{resource: {cluster: true}, actions: ['listDatabases']}], + roles: [] + }); + + admin.createRole({ + role: 'specificCollection', + privileges: [{resource: {db: "db0", collection: "baz"}, actions: ['find']}], + roles: [] + }); + + admin.createRole({ + role: 'sharedNameCollections', + privileges: [{resource: {db: "", collection: "baz"}, actions: ['find']}], + roles: [] + }); + + // Make db0, db2, db4, db6 readable to user1 abd user3. + // Make db0, db1, db2, db3 read/writable to user 2 and user3. + function makeRole(perm, dbNum) { + return {role: perm, db: ("db" + dbNum)}; + } + const readEven = [0, 2, 4, 6].map(function(i) { + return makeRole("read", i); + }); + const readWriteLow = [0, 1, 2, 3].map(function(i) { + return makeRole("readWrite", i); + }); + admin.createUser({user: 'user1', pwd: 'pass', roles: readEven}); + admin.createUser({user: 'user2', pwd: 'pass', roles: readWriteLow}); + admin.createUser({user: 'user3', pwd: 'pass', roles: readEven.concat(readWriteLow)}); + + // Make db4 readable by user 4, and let them list all dbs. + // Make db5 readable by user 5, and let them list all dbs. + // Make collection baz in db0 findable by user6, and let them list db0. + // Make all baz collections findable by user7, and let them list all dbs. + admin.createUser({user: 'user4', pwd: 'pass', roles: [makeRole('read', 4), 'dbLister']}); + admin.createUser({user: 'user5', pwd: 'pass', roles: [makeRole('read', 5), 'dbLister']}); + admin.createUser({user: 'user6', pwd: 'pass', roles: ['specificCollection']}); + admin.createUser({user: 'user7', pwd: 'pass', roles: ['sharedNameCollections']}); + admin.logout(); + + const admin_dbs = ["admin", "db0", "db1", "db2", "db3", "db4", "db5", "db6", "db7"]; + + [{user: "user1", dbs: ["db0", "db2", "db4", "db6"]}, + {user: "user2", dbs: ["db0", "db1", "db2", "db3"]}, + {user: "user3", dbs: ["db0", "db1", "db2", "db3", "db4", "db6"]}, + {user: "user4", dbs: admin_dbs, authDbs: ["db4"]}, + {user: "user5", dbs: admin_dbs, authDbs: ["db5"]}, + {user: "user6", dbs: ["db0"]}, + {user: "user7", dbs: admin_dbs}, + {user: "admin", dbs: admin_dbs, authDbs: admin_dbs}, + ].forEach(function(test) { + function filterSpecial(db) { + // Returning of local/config varies with sharding/mobile/etc.. + // Ignore these for simplicity. + return (db !== 'local') && (db !== 'config'); } - const readEven = [0, 2, 4, 6].map(function(i) { - return makeRole("read", i); - }); - const readWriteLow = [0, 1, 2, 3].map(function(i) { - return makeRole("readWrite", i); - }); - admin.createUser({user: 'user1', pwd: 'pass', roles: readEven}); - admin.createUser({user: 'user2', pwd: 'pass', roles: readWriteLow}); - admin.createUser({user: 'user3', pwd: 'pass', roles: readEven.concat(readWriteLow)}); - - // Make db4 readable by user 4, and let them list all dbs. - // Make db5 readable by user 5, and let them list all dbs. - // Make collection baz in db0 findable by user6, and let them list db0. - // Make all baz collections findable by user7, and let them list all dbs. - admin.createUser({user: 'user4', pwd: 'pass', roles: [makeRole('read', 4), 'dbLister']}); - admin.createUser({user: 'user5', pwd: 'pass', roles: [makeRole('read', 5), 'dbLister']}); - admin.createUser({user: 'user6', pwd: 'pass', roles: ['specificCollection']}); - admin.createUser({user: 'user7', pwd: 'pass', roles: ['sharedNameCollections']}); - admin.logout(); - const admin_dbs = ["admin", "db0", "db1", "db2", "db3", "db4", "db5", "db6", "db7"]; - - [{user: "user1", dbs: ["db0", "db2", "db4", "db6"]}, - {user: "user2", dbs: ["db0", "db1", "db2", "db3"]}, - {user: "user3", dbs: ["db0", "db1", "db2", "db3", "db4", "db6"]}, - {user: "user4", dbs: admin_dbs, authDbs: ["db4"]}, - {user: "user5", dbs: admin_dbs, authDbs: ["db5"]}, - {user: "user6", dbs: ["db0"]}, - {user: "user7", dbs: admin_dbs}, - {user: "admin", dbs: admin_dbs, authDbs: admin_dbs}, - ].forEach(function(test) { - function filterSpecial(db) { - // Returning of local/config varies with sharding/mobile/etc.. - // Ignore these for simplicity. - return (db !== 'local') && (db !== 'config'); - } - - // Invoking {listDatabases: 1} directly. - function tryList(cmd, expect_dbs) { - const dbs = assert.commandWorked(admin.runCommand(cmd)); - assert.eq(dbs.databases - .map(function(db) { - return db.name; - }) - .filter(filterSpecial) - .sort(), - expect_dbs, - test.user + " permissions"); - } + // Invoking {listDatabases: 1} directly. + function tryList(cmd, expect_dbs) { + const dbs = assert.commandWorked(admin.runCommand(cmd)); + assert.eq(dbs.databases + .map(function(db) { + return db.name; + }) + .filter(filterSpecial) + .sort(), + expect_dbs, + test.user + " permissions"); + } - admin.auth(test.user, 'pass'); - tryList({listDatabases: 1}, test.dbs); - tryList({listDatabases: 1, authorizedDatabases: true}, test.authDbs || test.dbs); + admin.auth(test.user, 'pass'); + tryList({listDatabases: 1}, test.dbs); + tryList({listDatabases: 1, authorizedDatabases: true}, test.authDbs || test.dbs); - if (test.authDbs) { - tryList({listDatabases: 1, authorizedDatabases: false}, test.dbs); - } else { - // Users without listDatabases cluster perm may not - // request authorizedDatabases: false. - assert.throws(tryList, [{listDatabases: 1, authorizedDatabases: false}, test.dbs]); - } + if (test.authDbs) { + tryList({listDatabases: 1, authorizedDatabases: false}, test.dbs); + } else { + // Users without listDatabases cluster perm may not + // request authorizedDatabases: false. + assert.throws(tryList, [{listDatabases: 1, authorizedDatabases: false}, test.dbs]); + } - // Test using shell helper Mongo.getDBs(). - assert.eq(mongod.getDBs(undefined, {}, true).filter(filterSpecial), - test.dbs, - "Shell helper speaking to same version"); - if (test.user !== 'admin' && test.user !== "user7") { - // Admin and user7 don't have an explicit list of DBs to parse. - assert.eq(mongod._getDatabaseNamesFromPrivileges(), test.authDbs || test.dbs); - - // Test (non-admin) call to Mongo.getDBs() on a < 4.0 MongoD - // by injecting a command failure into Mongo.adminCommand(). - // This will allow us to resemble a < 4.0 server. - const adminCommandFunction = mongod.adminCommand; - const adminCommandMethod = adminCommandFunction.bind(mongod); - - try { - mongod.adminCommand = function(cmd) { - if (cmd.hasOwnProperty('listDatabases')) { - return { - ok: 0, - errmsg: 'Stubbed command failure: ' + tojson(cmd), - code: ErrorCodes.Unauthorized, - codeName: 'Unauthorized' - }; - } - return adminCommandMethod(cmd); - }; - // Command fails, but we dispatch via _getDatabaseNamesFromPrivileges(). - assert.eq(mongod.getDBs().databases.map(function(x) { - return x.name; - }), - test.authDbs || test.dbs); - - // Still dispatches with explicit nameOnly===true, returns only names. - assert.eq(mongod.getDBs(undefined, undefined, true), test.authDbs || test.dbs); - - // Command fails and unable to dispatch because nameOnly !== true. - assert.throws(() => mongod.getDBs(undefined, undefined, false)); - - // Command fails and unable to dispatch because filter is not empty. - assert.throws(() => mongod.getDBs(undefined, {name: 'foo'})); - } finally { - mongod.adminCommand = adminCommandFunction; - } + // Test using shell helper Mongo.getDBs(). + assert.eq(mongod.getDBs(undefined, {}, true).filter(filterSpecial), + test.dbs, + "Shell helper speaking to same version"); + if (test.user !== 'admin' && test.user !== "user7") { + // Admin and user7 don't have an explicit list of DBs to parse. + assert.eq(mongod._getDatabaseNamesFromPrivileges(), test.authDbs || test.dbs); + + // Test (non-admin) call to Mongo.getDBs() on a < 4.0 MongoD + // by injecting a command failure into Mongo.adminCommand(). + // This will allow us to resemble a < 4.0 server. + const adminCommandFunction = mongod.adminCommand; + const adminCommandMethod = adminCommandFunction.bind(mongod); + + try { + mongod.adminCommand = function(cmd) { + if (cmd.hasOwnProperty('listDatabases')) { + return { + ok: 0, + errmsg: 'Stubbed command failure: ' + tojson(cmd), + code: ErrorCodes.Unauthorized, + codeName: 'Unauthorized' + }; + } + return adminCommandMethod(cmd); + }; + // Command fails, but we dispatch via _getDatabaseNamesFromPrivileges(). + assert.eq(mongod.getDBs().databases.map(function(x) { + return x.name; + }), + test.authDbs || test.dbs); + + // Still dispatches with explicit nameOnly===true, returns only names. + assert.eq(mongod.getDBs(undefined, undefined, true), test.authDbs || test.dbs); + + // Command fails and unable to dispatch because nameOnly !== true. + assert.throws(() => mongod.getDBs(undefined, undefined, false)); + + // Command fails and unable to dispatch because filter is not empty. + assert.throws(() => mongod.getDBs(undefined, {name: 'foo'})); + } finally { + mongod.adminCommand = adminCommandFunction; } + } - admin.logout(); - }); - } - - const mongod = MongoRunner.runMongod({auth: ""}); - runTest(mongod); - MongoRunner.stopMongod(mongod); - - if (jsTest.options().storageEngine !== "mobile") { - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runTest(st.s0); - st.stop(); - } + admin.logout(); + }); +} + +const mongod = MongoRunner.runMongod({auth: ""}); +runTest(mongod); +MongoRunner.stopMongod(mongod); + +if (jsTest.options().storageEngine !== "mobile") { + // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. + const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} + }); + runTest(st.s0); + st.stop(); +} })(); diff --git a/jstests/auth/list_local_sessions.js b/jstests/auth/list_local_sessions.js index b943ba45955..3c16df48b8e 100644 --- a/jstests/auth/list_local_sessions.js +++ b/jstests/auth/list_local_sessions.js @@ -1,76 +1,75 @@ // All tests for the $listLocalSessions aggregation stage. (function() { - 'use strict'; - load('jstests/aggregation/extras/utils.js'); +'use strict'; +load('jstests/aggregation/extras/utils.js'); - // This test makes assertions about the number of sessions, which are not compatible with - // implicit sessions. - TestData.disableImplicitSessions = true; +// This test makes assertions about the number of sessions, which are not compatible with +// implicit sessions. +TestData.disableImplicitSessions = true; - function runListLocalSessionsTest(mongod) { - assert(mongod); - const admin = mongod.getDB('admin'); - const db = mongod.getDB("test"); +function runListLocalSessionsTest(mongod) { + assert(mongod); + const admin = mongod.getDB('admin'); + const db = mongod.getDB("test"); - const pipeline = [{'$listLocalSessions': {}}]; - function listLocalSessions() { - return admin.aggregate(pipeline); - } + const pipeline = [{'$listLocalSessions': {}}]; + function listLocalSessions() { + return admin.aggregate(pipeline); + } - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); - db.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); - db.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.logout(); + db.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); + db.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); + admin.logout(); - // Shouldn't be able to listLocalSessions when not logged in. - assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); + // Shouldn't be able to listLocalSessions when not logged in. + assertErrorCode(admin, pipeline, ErrorCodes.Unauthorized); - // Start a new session and capture its sessionId. - assert(db.auth('user1', 'pass')); - const myid = assert.commandWorked(db.runCommand({startSession: 1})).id.id; - assert(myid !== undefined); + // Start a new session and capture its sessionId. + assert(db.auth('user1', 'pass')); + const myid = assert.commandWorked(db.runCommand({startSession: 1})).id.id; + assert(myid !== undefined); - // Ensure that the cache now contains the session. - const resultArray = assert.doesNotThrow(listLocalSessions).toArray(); - assert.eq(resultArray.length, 1); - const cacheid = resultArray[0]._id.id; - const myuid = resultArray[0]._id.uid; - assert(cacheid !== undefined); - assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); + // Ensure that the cache now contains the session. + const resultArray = assert.doesNotThrow(listLocalSessions).toArray(); + assert.eq(resultArray.length, 1); + const cacheid = resultArray[0]._id.id; + const myuid = resultArray[0]._id.uid; + assert(cacheid !== undefined); + assert.eq(0, bsonWoCompare({x: cacheid}, {x: myid})); - // Try asking for the session by username. - function listMyLocalSessions() { - return admin.aggregate( - [{'$listLocalSessions': {users: [{user: "user1", db: "test"}]}}]); - } - const resultArrayMine = assert.doesNotThrow(listMyLocalSessions).toArray(); - assert.eq(bsonWoCompare(resultArray, resultArrayMine), 0); + // Try asking for the session by username. + function listMyLocalSessions() { + return admin.aggregate([{'$listLocalSessions': {users: [{user: "user1", db: "test"}]}}]); + } + const resultArrayMine = assert.doesNotThrow(listMyLocalSessions).toArray(); + assert.eq(bsonWoCompare(resultArray, resultArrayMine), 0); - // Ensure that changing users hides the session. - assert(db.auth('user2', 'pass')); - const otherArray = assert.doesNotThrow(listLocalSessions).toArray(); - assert.eq(otherArray.length, 0); + // Ensure that changing users hides the session. + assert(db.auth('user2', 'pass')); + const otherArray = assert.doesNotThrow(listLocalSessions).toArray(); + assert.eq(otherArray.length, 0); - // Ensure that one user can not explicitly ask for another's sessions. - assertErrorCode(admin, - [{'$listLocalSessions': {users: [{user: "user1", db: "test"}]}}], - ErrorCodes.Unauthorized); - } + // Ensure that one user can not explicitly ask for another's sessions. + assertErrorCode(admin, + [{'$listLocalSessions': {users: [{user: "user1", db: "test"}]}}], + ErrorCodes.Unauthorized); +} - const mongod = MongoRunner.runMongod({auth: ""}); - runListLocalSessionsTest(mongod); - MongoRunner.stopMongod(mongod); +const mongod = MongoRunner.runMongod({auth: ""}); +runListLocalSessionsTest(mongod); +MongoRunner.stopMongod(mongod); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runListLocalSessionsTest(st.s0); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runListLocalSessionsTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/list_sessions.js b/jstests/auth/list_sessions.js index 2b6c8a0f8f1..f91218d22e4 100644 --- a/jstests/auth/list_sessions.js +++ b/jstests/auth/list_sessions.js @@ -4,85 +4,85 @@ */ (function() { - 'use strict'; - load('jstests/aggregation/extras/utils.js'); - - // This test makes assertions about the number of sessions, which are not compatible with - // implicit sessions. - TestData.disableImplicitSessions = true; - - function runListSessionsTest(mongod) { - assert(mongod); - const admin = mongod.getDB('admin'); - const config = mongod.getDB('config'); - - const pipeline = [{'$listSessions': {}}]; - function listSessions() { - return config.system.sessions.aggregate(pipeline); - } - - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - - admin.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.logout(); - - // Fail when not logged in. - assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); - - // Start a new session and capture its sessionId. - assert(admin.auth('user1', 'pass')); - const myid = assert.commandWorked(admin.runCommand({startSession: 1})).id.id; - assert(myid !== undefined); - - // Sync cache to collection and ensure it arrived. - assert.commandWorked(admin.runCommand({refreshLogicalSessionCacheNow: 1})); - const resultArray = listSessions().toArray(); - assert.eq(resultArray.length, 1); - const cacheid = resultArray[0]._id.id; - assert(cacheid !== undefined); - assert.eq(bsonWoCompare(cacheid, myid), 0); - - // Ask again using explicit UID. - const user1Pipeline = [{'$listSessions': {users: [{user: "user1", db: "admin"}]}}]; - function listUser1Sessions() { - return config.system.sessions.aggregate(user1Pipeline); - } - const resultArrayMine = listUser1Sessions().toArray(); - assert.eq(bsonWoCompare(resultArray, resultArrayMine), 0); - - // Make sure pipelining other collections fail - assertErrorCode(admin.system.collections, pipeline, ErrorCodes.InvalidNamespace); - - // Ensure that changing users hides the session everwhere. - assert(admin.auth('user2', 'pass')); - assert.eq(listSessions().toArray().length, 0); - - // Ensure users can't view either other's sessions. - assertErrorCode(config.system.sessions, user1Pipeline, ErrorCodes.Unauthorized); - - if (true) { - // TODO SERVER-29141: Support forcing pipelines to run on mongos - return; - } - function listLocalSessions() { - return config.aggregate([{'$listLocalSessions': {}}]); - } - assert.eq(listLocalSessions().toArray().length, 0); +'use strict'; +load('jstests/aggregation/extras/utils.js'); + +// This test makes assertions about the number of sessions, which are not compatible with +// implicit sessions. +TestData.disableImplicitSessions = true; + +function runListSessionsTest(mongod) { + assert(mongod); + const admin = mongod.getDB('admin'); + const config = mongod.getDB('config'); + + const pipeline = [{'$listSessions': {}}]; + function listSessions() { + return config.system.sessions.aggregate(pipeline); + } + + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + + admin.createUser({user: 'user1', pwd: 'pass', roles: jsTest.basicUserRoles}); + admin.createUser({user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles}); + admin.logout(); + + // Fail when not logged in. + assertErrorCode(config.system.sessions, pipeline, ErrorCodes.Unauthorized); + + // Start a new session and capture its sessionId. + assert(admin.auth('user1', 'pass')); + const myid = assert.commandWorked(admin.runCommand({startSession: 1})).id.id; + assert(myid !== undefined); + + // Sync cache to collection and ensure it arrived. + assert.commandWorked(admin.runCommand({refreshLogicalSessionCacheNow: 1})); + const resultArray = listSessions().toArray(); + assert.eq(resultArray.length, 1); + const cacheid = resultArray[0]._id.id; + assert(cacheid !== undefined); + assert.eq(bsonWoCompare(cacheid, myid), 0); + + // Ask again using explicit UID. + const user1Pipeline = [{'$listSessions': {users: [{user: "user1", db: "admin"}]}}]; + function listUser1Sessions() { + return config.system.sessions.aggregate(user1Pipeline); } + const resultArrayMine = listUser1Sessions().toArray(); + assert.eq(bsonWoCompare(resultArray, resultArrayMine), 0); - const mongod = MongoRunner.runMongod({auth: ""}); - runListSessionsTest(mongod); - MongoRunner.stopMongod(mongod); - - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runListSessionsTest(st.s0); - st.stop(); + // Make sure pipelining other collections fail + assertErrorCode(admin.system.collections, pipeline, ErrorCodes.InvalidNamespace); + + // Ensure that changing users hides the session everwhere. + assert(admin.auth('user2', 'pass')); + assert.eq(listSessions().toArray().length, 0); + + // Ensure users can't view either other's sessions. + assertErrorCode(config.system.sessions, user1Pipeline, ErrorCodes.Unauthorized); + + if (true) { + // TODO SERVER-29141: Support forcing pipelines to run on mongos + return; + } + function listLocalSessions() { + return config.aggregate([{'$listLocalSessions': {}}]); + } + assert.eq(listLocalSessions().toArray().length, 0); +} + +const mongod = MongoRunner.runMongod({auth: ""}); +runListSessionsTest(mongod); +MongoRunner.stopMongod(mongod); + +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runListSessionsTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/listcommands_preauth.js b/jstests/auth/listcommands_preauth.js index 4967628bc22..fae33cf65db 100644 --- a/jstests/auth/listcommands_preauth.js +++ b/jstests/auth/listcommands_preauth.js @@ -1,38 +1,36 @@ // Make sure that listCommands doesn't require authentication. (function() { - 'use strict'; +'use strict'; - function runTest(conn) { - const admin = conn.getDB('admin'); +function runTest(conn) { + const admin = conn.getDB('admin'); - // Commands should succeed in auth-bypass mode regardless of requiresAuth(). - assert.commandWorked(admin.runCommand({listDatabases: 1}), - "listDatabases shouldn't work pre-auth"); - assert.commandWorked(admin.runCommand({listCommands: 1}), - "listCommands should work pre-auth"); + // Commands should succeed in auth-bypass mode regardless of requiresAuth(). + assert.commandWorked(admin.runCommand({listDatabases: 1}), + "listDatabases shouldn't work pre-auth"); + assert.commandWorked(admin.runCommand({listCommands: 1}), "listCommands should work pre-auth"); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - // listDatabases should now fail, because auth bypass is no longer valid. - assert.commandFailed(admin.runCommand({listDatabases: 1}), - "listDatabases shouldn't work pre-auth"); - // listCommands should STILL work, because it does not require auth. - assert.commandWorked(admin.runCommand({listCommands: 1}), - "listCommands should work pre-auth"); - } + // listDatabases should now fail, because auth bypass is no longer valid. + assert.commandFailed(admin.runCommand({listDatabases: 1}), + "listDatabases shouldn't work pre-auth"); + // listCommands should STILL work, because it does not require auth. + assert.commandWorked(admin.runCommand({listCommands: 1}), "listCommands should work pre-auth"); +} - const mongod = MongoRunner.runMongod({auth: ""}); - runTest(mongod); - MongoRunner.stopMongod(mongod); +const mongod = MongoRunner.runMongod({auth: ""}); +runTest(mongod); +MongoRunner.stopMongod(mongod); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = new ShardingTest({ - shards: 1, - mongos: 1, - config: 1, - other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} - }); - runTest(st.s0); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + other: {keyFile: 'jstests/libs/key1', shardAsReplicaSet: false} +}); +runTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/logs_include_client_info.js b/jstests/auth/logs_include_client_info.js index 5e793100686..31594a60de5 100644 --- a/jstests/auth/logs_include_client_info.js +++ b/jstests/auth/logs_include_client_info.js @@ -2,28 +2,28 @@ // address of the client attempting to authenticate. (function() { - const conn = MongoRunner.runMongod({auth: ""}); - const admin = conn.getDB("admin"); +const conn = MongoRunner.runMongod({auth: ""}); +const admin = conn.getDB("admin"); - admin.createUser({ - user: "root", - pwd: "root", - roles: ["root"], - }); +admin.createUser({ + user: "root", + pwd: "root", + roles: ["root"], +}); - assert(admin.auth("root", "root")); +assert(admin.auth("root", "root")); - const failConn = new Mongo(conn.host); - failConn.getDB("admin").auth("root", "toot"); +const failConn = new Mongo(conn.host); +failConn.getDB("admin").auth("root", "toot"); - const log = assert.commandWorked(admin.runCommand({getLog: "global"})).log; +const log = assert.commandWorked(admin.runCommand({getLog: "global"})).log; - const successRegex = - /Successfully authenticated as principal root on admin from client (?:\d{1,3}\.){3}\d{1,3}:\d+/; - const failRegex = - /SASL SCRAM-SHA-\d+ authentication failed for root on admin from client (?:\d{1,3}\.){3}\d{1,3}:\d+/; +const successRegex = + /Successfully authenticated as principal root on admin from client (?:\d{1,3}\.){3}\d{1,3}:\d+/; +const failRegex = + /SASL SCRAM-SHA-\d+ authentication failed for root on admin from client (?:\d{1,3}\.){3}\d{1,3}:\d+/; - assert(log.some((line) => successRegex.test(line))); - assert(log.some((line) => failRegex.test(line))); - MongoRunner.stopMongod(conn); +assert(log.some((line) => successRegex.test(line))); +assert(log.some((line) => failRegex.test(line))); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/mongoURIAuth.js b/jstests/auth/mongoURIAuth.js index 7f60b2e750e..0ceff7b4b31 100644 --- a/jstests/auth/mongoURIAuth.js +++ b/jstests/auth/mongoURIAuth.js @@ -2,71 +2,69 @@ // the specified auth mechanism. (function() { - 'use strict'; +'use strict'; - const runURIAuthTest = function(userMech, uriMech, authMechanism, regexMechanism) { - const conn = MongoRunner.runMongod({auth: ""}); - const adminDB = conn.getDB("admin"); +const runURIAuthTest = function(userMech, uriMech, authMechanism, regexMechanism) { + const conn = MongoRunner.runMongod({auth: ""}); + const adminDB = conn.getDB("admin"); + adminDB.createUser({ + user: "u", + pwd: "p", + roles: ["root"], + + }); + adminDB.auth("u", "p"); + adminDB.setLogLevel(2, "command"); + + if (userMech) { adminDB.createUser({ - user: "u", - pwd: "p", + user: "user", + pwd: "password", roles: ["root"], - + mechanisms: [authMechanism], }); - adminDB.auth("u", "p"); - adminDB.setLogLevel(2, "command"); - - if (userMech) { - adminDB.createUser({ - user: "user", - pwd: "password", - roles: ["root"], - mechanisms: [authMechanism], - }); - } else { - adminDB.createUser({ - user: "user", - pwd: "password", - roles: ["root"], - }); - } - - var uri; + } else { + adminDB.createUser({ + user: "user", + pwd: "password", + roles: ["root"], + }); + } - if (uriMech) { - uri = "mongodb://user:password@localhost:" + conn.port + "/admin?authMechanism=" + - authMechanism; - } else { - uri = "mongodb://user:password@localhost:" + conn.port; - } + var uri; - var shell = runMongoProgram('./mongo', uri, "--eval", "db.getName()"); - assert.eq(shell, 0, "Should be able to connect with specified params."); + if (uriMech) { + uri = "mongodb://user:password@localhost:" + conn.port + + "/admin?authMechanism=" + authMechanism; + } else { + uri = "mongodb://user:password@localhost:" + conn.port; + } - const log = adminDB.runCommand({getLog: "global"}); - adminDB.logout(); - const matches = tojson(log.log).match(regexMechanism); - assert(matches); - assert.eq(2, matches.length); + var shell = runMongoProgram('./mongo', uri, "--eval", "db.getName()"); + assert.eq(shell, 0, "Should be able to connect with specified params."); - MongoRunner.stopMongod(conn); - }; + const log = adminDB.runCommand({getLog: "global"}); + adminDB.logout(); + const matches = tojson(log.log).match(regexMechanism); + assert(matches); + assert.eq(2, matches.length); - const SCRAM_SHA_256 = "SCRAM-SHA-256"; - const SCRAM_SHA_1 = "SCRAM-SHA-1"; + MongoRunner.stopMongod(conn); +}; - const SCRAM_SHA_256_regex = /saslStart.*mechanism:.*SCRAM-SHA-256/g; - const SCRAM_SHA_1_regex = /saslStart.*mechanism:.*SCRAM-SHA-1/g; +const SCRAM_SHA_256 = "SCRAM-SHA-256"; +const SCRAM_SHA_1 = "SCRAM-SHA-1"; - jsTestLog("Test that a mechanism specified in the URI is the chosen authentication method."); - runURIAuthTest(false, true, SCRAM_SHA_256, SCRAM_SHA_256_regex); +const SCRAM_SHA_256_regex = /saslStart.*mechanism:.*SCRAM-SHA-256/g; +const SCRAM_SHA_1_regex = /saslStart.*mechanism:.*SCRAM-SHA-1/g; - jsTestLog( - "Test that a mechanism specified in CreateUser() is the chosen authentication method."); - runURIAuthTest(true, false, SCRAM_SHA_1, SCRAM_SHA_1_regex); +jsTestLog("Test that a mechanism specified in the URI is the chosen authentication method."); +runURIAuthTest(false, true, SCRAM_SHA_256, SCRAM_SHA_256_regex); - jsTestLog("Test that SCRAM-SHA-1 is the default authentication method."); - runURIAuthTest(false, false, SCRAM_SHA_256, SCRAM_SHA_256_regex); +jsTestLog("Test that a mechanism specified in CreateUser() is the chosen authentication method."); +runURIAuthTest(true, false, SCRAM_SHA_1, SCRAM_SHA_1_regex); +jsTestLog("Test that SCRAM-SHA-1 is the default authentication method."); +runURIAuthTest(false, false, SCRAM_SHA_256, SCRAM_SHA_256_regex); })();
\ No newline at end of file diff --git a/jstests/auth/mongos_cache_invalidation.js b/jstests/auth/mongos_cache_invalidation.js index 1f7064f558d..0917cb68f36 100644 --- a/jstests/auth/mongos_cache_invalidation.js +++ b/jstests/auth/mongos_cache_invalidation.js @@ -120,7 +120,6 @@ db3.auth('spencer', 'pwd'); db3.adminCommand("invalidateUserCache"); assert.writeOK(db3.foo.update({}, {$inc: {a: 1}})); assert.eq(4, db3.foo.findOne().a); - })(); (function testRevokingPrivileges() { @@ -212,7 +211,6 @@ db3.auth('spencer', 'pwd'); // We manually invalidate the cache on s2/db3. db3.adminCommand("invalidateUserCache"); assert.commandFailedWithCode(db3.foo.runCommand("collStats"), authzErrorCode); - })(); st.stop(); diff --git a/jstests/auth/pinned_users.js b/jstests/auth/pinned_users.js index f57bfa85f74..72e6b21fb8b 100644 --- a/jstests/auth/pinned_users.js +++ b/jstests/auth/pinned_users.js @@ -8,191 +8,188 @@ * */ (function() { - 'use strict'; - jsTest.setOption("enableTestCommands", true); - // Start a mongod with the user cache size set to zero, so we know that users who have - // logged out always get fetched cleanly from disk. - const rs = new ReplSetTest({ - nodes: 3, - nodeOptions: {auth: "", setParameter: "authorizationManagerCacheSize=0"}, - keyFile: "jstests/libs/key1" - }); - - rs.startSet(); - rs.initiate(); - const mongod = rs.getPrimary(); - const admin = mongod.getDB("admin"); - - admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); - admin.auth("admin", "admin"); - - // Mark the "admin2" user as pinned in memory, we'll use this later on to recover from - // the deadlock - assert.commandWorked(admin.runCommand({ - setParameter: 1, - logLevel: 2, - authorizationManagerPinnedUsers: [ - {user: "admin2", db: "admin"}, - ], - })); - - admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); - - let secondConn = new Mongo(mongod.host); - let secondAdmin = secondConn.getDB("admin"); - secondAdmin.auth("admin2", "admin"); - - // Invalidate the user cache so we know only "admin" is in there - assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); +'use strict'; +jsTest.setOption("enableTestCommands", true); +// Start a mongod with the user cache size set to zero, so we know that users who have +// logged out always get fetched cleanly from disk. +const rs = new ReplSetTest({ + nodes: 3, + nodeOptions: {auth: "", setParameter: "authorizationManagerCacheSize=0"}, + keyFile: "jstests/libs/key1" +}); + +rs.startSet(); +rs.initiate(); +const mongod = rs.getPrimary(); +const admin = mongod.getDB("admin"); + +admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); +admin.auth("admin", "admin"); + +// Mark the "admin2" user as pinned in memory, we'll use this later on to recover from +// the deadlock +assert.commandWorked(admin.runCommand({ + setParameter: 1, + logLevel: 2, + authorizationManagerPinnedUsers: [ + {user: "admin2", db: "admin"}, + ], +})); + +admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); + +let secondConn = new Mongo(mongod.host); +let secondAdmin = secondConn.getDB("admin"); +secondAdmin.auth("admin2", "admin"); + +// Invalidate the user cache so we know only "admin" is in there +assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); +assert.soon(function() { + let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); + print("User cache after initialization: ", tojson(cacheContents)); + + const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); + return cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); +}); + +const waitForCommand = function(waitingFor, opFilter) { + let opId = -1; assert.soon(function() { - let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); - print("User cache after initialization: ", tojson(cacheContents)); - - const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); - return cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); + print(`Checking for ${waitingFor}`); + const curopRes = admin.currentOp(); + assert.commandWorked(curopRes); + const foundOp = curopRes["inprog"].filter(opFilter); + + if (foundOp.length == 1) { + opId = foundOp[0]["opid"]; + } + return (foundOp.length == 1); }); - - const waitForCommand = function(waitingFor, opFilter) { - let opId = -1; - assert.soon(function() { - print(`Checking for ${waitingFor}`); - const curopRes = admin.currentOp(); - assert.commandWorked(curopRes); - const foundOp = curopRes["inprog"].filter(opFilter); - - if (foundOp.length == 1) { - opId = foundOp[0]["opid"]; - } - return (foundOp.length == 1); - }); - return opId; - }; - - // The deadlock happens in two phases. First we run a command that acquires a read lock and - // holds it for forever. - let readLockShell = startParallelShell(function() { - assert.eq(db.getSiblingDB("admin").auth("admin", "admin"), 1); - assert.commandFailed(db.adminCommand( - {sleep: 1, secs: 500, lock: "r", lockTarget: "admin", $comment: "Read lock sleep"})); - }, mongod.port); - - // Wait for that command to appear in currentOp - const readID = waitForCommand( - "readlock", - op => (op["ns"] == "admin.$cmd" && op["command"]["$comment"] == "Read lock sleep")); - - // Then we run a command that tries to acquire a write lock, which will wait for forever - // because we're already holding a read lock, but will also prevent any new read locks from - // being taken. - let writeLockShell = startParallelShell(function() { - assert.eq(db.getSiblingDB("admin").auth("admin", "admin"), 1); - assert.commandFailed(db.adminCommand( - {sleep: 1, secs: 500, lock: "w", lockTarget: "admin", $comment: "Write lock sleep"})); - }, mongod.port); - - // Wait for that to appear in currentOp - const writeID = waitForCommand( - "writeLock", - op => (op["ns"] == "admin.$cmd" && op["command"]["$comment"] == "Write lock sleep")); - - print("killing ops and moving on!"); - - // If "admin2" wasn't pinned in memory, then these would hang. - assert.commandWorked(secondAdmin.currentOp()); - assert.commandWorked(secondAdmin.killOp(readID)); - assert.commandWorked(secondAdmin.killOp(writeID)); - - readLockShell(); - writeLockShell(); - - admin.logout(); - secondAdmin.logout(); - rs.stopSet(); + return opId; +}; + +// The deadlock happens in two phases. First we run a command that acquires a read lock and +// holds it for forever. +let readLockShell = startParallelShell(function() { + assert.eq(db.getSiblingDB("admin").auth("admin", "admin"), 1); + assert.commandFailed(db.adminCommand( + {sleep: 1, secs: 500, lock: "r", lockTarget: "admin", $comment: "Read lock sleep"})); +}, mongod.port); + +// Wait for that command to appear in currentOp +const readID = waitForCommand( + "readlock", op => (op["ns"] == "admin.$cmd" && op["command"]["$comment"] == "Read lock sleep")); + +// Then we run a command that tries to acquire a write lock, which will wait for forever +// because we're already holding a read lock, but will also prevent any new read locks from +// being taken. +let writeLockShell = startParallelShell(function() { + assert.eq(db.getSiblingDB("admin").auth("admin", "admin"), 1); + assert.commandFailed(db.adminCommand( + {sleep: 1, secs: 500, lock: "w", lockTarget: "admin", $comment: "Write lock sleep"})); +}, mongod.port); + +// Wait for that to appear in currentOp +const writeID = waitForCommand( + "writeLock", + op => (op["ns"] == "admin.$cmd" && op["command"]["$comment"] == "Write lock sleep")); + +print("killing ops and moving on!"); + +// If "admin2" wasn't pinned in memory, then these would hang. +assert.commandWorked(secondAdmin.currentOp()); +assert.commandWorked(secondAdmin.killOp(readID)); +assert.commandWorked(secondAdmin.killOp(writeID)); + +readLockShell(); +writeLockShell(); + +admin.logout(); +secondAdmin.logout(); +rs.stopSet(); })(); // This checks that removing a user document actually unpins a user. This is a round-about way // of making sure that updates to the authz manager by the opObserver correctly invalidates the // cache and that pinned users don't stick around after they're removed. (function() { - 'use strict'; - jsTest.setOption("enableTestCommands", true); - // Start a mongod with the user cache size set to zero, so we know that users who have - // logged out always get fetched cleanly from disk. - const mongod = - MongoRunner.runMongod({auth: "", setParameter: "authorizationManagerCacheSize=0"}); - let admin = mongod.getDB("admin"); - - admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); - admin.auth("admin", "admin"); - - // Mark the "admin2" user as pinned in memory - assert.commandWorked(admin.runCommand({ - setParameter: 1, - logLevel: 2, - authorizationManagerPinnedUsers: [ - {user: "admin2", db: "admin"}, - ], - })); - - admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); - - // Invalidate the user cache so we know only "admin" is in there - assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); - print("User cache after initialization: ", - tojson(admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray())); - - assert.commandWorked(admin.getCollection("system.users").remove({user: "admin2"})); - - print("User cache after removing user doc: ", - tojson(admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray())); - - assert.eq(admin.auth("admin2", "admin"), 0); - MongoRunner.stopMongod(mongod); +'use strict'; +jsTest.setOption("enableTestCommands", true); +// Start a mongod with the user cache size set to zero, so we know that users who have +// logged out always get fetched cleanly from disk. +const mongod = MongoRunner.runMongod({auth: "", setParameter: "authorizationManagerCacheSize=0"}); +let admin = mongod.getDB("admin"); + +admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); +admin.auth("admin", "admin"); + +// Mark the "admin2" user as pinned in memory +assert.commandWorked(admin.runCommand({ + setParameter: 1, + logLevel: 2, + authorizationManagerPinnedUsers: [ + {user: "admin2", db: "admin"}, + ], +})); + +admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); + +// Invalidate the user cache so we know only "admin" is in there +assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); +print("User cache after initialization: ", + tojson(admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray())); + +assert.commandWorked(admin.getCollection("system.users").remove({user: "admin2"})); + +print("User cache after removing user doc: ", + tojson(admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray())); + +assert.eq(admin.auth("admin2", "admin"), 0); +MongoRunner.stopMongod(mongod); })(); // This checks that clearing the pinned user list actually unpins a user. (function() { - 'use strict'; - jsTest.setOption("enableTestCommands", true); - // Start a mongod with the user cache size set to zero, so we know that users who have - // logged out always get fetched cleanly from disk. - const mongod = - MongoRunner.runMongod({auth: "", setParameter: "authorizationManagerCacheSize=0"}); - let admin = mongod.getDB("admin"); - - admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); - admin.auth("admin", "admin"); - - // Mark the "admin2" user as pinned in memory - assert.commandWorked(admin.runCommand({ - setParameter: 1, - logLevel: 2, - authorizationManagerPinnedUsers: [ - {user: "admin2", db: "admin"}, - ], - })); - - admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); - assert.soon(function() { - let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); - print("User cache after initialization: ", tojson(cacheContents)); - - const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); - return cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); - }); - - // Clear the pinned users list - assert.commandWorked(admin.runCommand({setParameter: 1, authorizationManagerPinnedUsers: []})); - - // Check that admin2 gets removed from the cache - assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); - assert.soon(function() { - let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); - print("User cache after initialization: ", tojson(cacheContents)); - - const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); - return !cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); - }); - - MongoRunner.stopMongod(mongod); +'use strict'; +jsTest.setOption("enableTestCommands", true); +// Start a mongod with the user cache size set to zero, so we know that users who have +// logged out always get fetched cleanly from disk. +const mongod = MongoRunner.runMongod({auth: "", setParameter: "authorizationManagerCacheSize=0"}); +let admin = mongod.getDB("admin"); + +admin.createUser({user: "admin", pwd: "admin", roles: ["root"]}); +admin.auth("admin", "admin"); + +// Mark the "admin2" user as pinned in memory +assert.commandWorked(admin.runCommand({ + setParameter: 1, + logLevel: 2, + authorizationManagerPinnedUsers: [ + {user: "admin2", db: "admin"}, + ], +})); + +admin.createUser({user: "admin2", pwd: "admin", roles: ["root"]}); +assert.soon(function() { + let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); + print("User cache after initialization: ", tojson(cacheContents)); + + const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); + return cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); +}); + +// Clear the pinned users list +assert.commandWorked(admin.runCommand({setParameter: 1, authorizationManagerPinnedUsers: []})); + +// Check that admin2 gets removed from the cache +assert.commandWorked(admin.runCommand({invalidateUserCache: 1})); +assert.soon(function() { + let cacheContents = admin.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); + print("User cache after initialization: ", tojson(cacheContents)); + + const admin2Doc = sortDoc({"username": "admin2", "db": "admin", "active": true}); + return !cacheContents.some((doc) => friendlyEqual(admin2Doc, sortDoc(doc))); +}); + +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/pre_auth_commands_with_sessions.js b/jstests/auth/pre_auth_commands_with_sessions.js index 0e440a01c13..19bee66efb6 100644 --- a/jstests/auth/pre_auth_commands_with_sessions.js +++ b/jstests/auth/pre_auth_commands_with_sessions.js @@ -1,52 +1,51 @@ (function() { - 'use strict'; - - var conn = MongoRunner.runMongod({auth: ""}); - var admin = conn.getDB("admin"); - var db = conn.getDB("otherdb"); - - admin.createUser({user: "admin", pwd: "pwd", roles: jsTest.adminUserRoles}); - admin.auth("admin", "pwd"); - db.createUser({user: "lily", pwd: "pwd", roles: jsTest.basicUserRoles}); +'use strict'; + +var conn = MongoRunner.runMongod({auth: ""}); +var admin = conn.getDB("admin"); +var db = conn.getDB("otherdb"); + +admin.createUser({user: "admin", pwd: "pwd", roles: jsTest.adminUserRoles}); +admin.auth("admin", "pwd"); +db.createUser({user: "lily", pwd: "pwd", roles: jsTest.basicUserRoles}); +admin.logout(); + +var testCommand = function(cmd) { + // Test that we can run a pre-auth command without authenticating. + var command = {[cmd]: 1}; + + assert.commandWorked(admin.runCommand(command)); + + // Test that we can authenticate and start a session + db.auth("lily", "pwd"); + var res = admin.runCommand({startSession: 1}); + assert.commandWorked(res); + var id = res.id; + + var commandWithSession = {[cmd]: 1, lsid: res.id}; + + // Test that we can run a pre-auth command with a session while + // the session owner is logged in (and the session gets ignored) + assert.commandWorked(db.runCommand(command), + "failed to run command " + cmd + " while logged in"); + assert.commandWorked(db.runCommand(commandWithSession), + "failed to run command " + cmd + " with session while logged in"); + + // Test that we can run a pre-auth command with a session while + // nobody is logged in (and the session gets ignored) + db.logout(); + assert.commandWorked(db.runCommand(command), + "failed to run command " + cmd + " without being logged in"); + assert.commandWorked(db.runCommand(commandWithSession), + "failed to run command " + cmd + " with session without being logged in"); + + db.logout(); admin.logout(); +}; - var testCommand = function(cmd) { - // Test that we can run a pre-auth command without authenticating. - var command = {[cmd]: 1}; - - assert.commandWorked(admin.runCommand(command)); - - // Test that we can authenticate and start a session - db.auth("lily", "pwd"); - var res = admin.runCommand({startSession: 1}); - assert.commandWorked(res); - var id = res.id; - - var commandWithSession = {[cmd]: 1, lsid: res.id}; - - // Test that we can run a pre-auth command with a session while - // the session owner is logged in (and the session gets ignored) - assert.commandWorked(db.runCommand(command), - "failed to run command " + cmd + " while logged in"); - assert.commandWorked(db.runCommand(commandWithSession), - "failed to run command " + cmd + " with session while logged in"); - - // Test that we can run a pre-auth command with a session while - // nobody is logged in (and the session gets ignored) - db.logout(); - assert.commandWorked(db.runCommand(command), - "failed to run command " + cmd + " without being logged in"); - assert.commandWorked( - db.runCommand(commandWithSession), - "failed to run command " + cmd + " with session without being logged in"); - - db.logout(); - admin.logout(); - }; - - var commands = ["ping", "ismaster"]; - for (var i = 0; i < commands.length; i++) { - testCommand(commands[i]); - } - MongoRunner.stopMongod(conn, null, {user: "admin", pwd: "pwd"}); +var commands = ["ping", "ismaster"]; +for (var i = 0; i < commands.length; i++) { + testCommand(commands[i]); +} +MongoRunner.stopMongod(conn, null, {user: "admin", pwd: "pwd"}); })(); diff --git a/jstests/auth/prepared_transaction.js b/jstests/auth/prepared_transaction.js index 2864dea5fd5..9605fe32973 100644 --- a/jstests/auth/prepared_transaction.js +++ b/jstests/auth/prepared_transaction.js @@ -6,200 +6,200 @@ * @tags: [uses_transactions, uses_prepare_transaction] */ (function() { - "use strict"; - - const rst = new ReplSetTest({nodes: 2, keyFile: "jstests/libs/key1"}); - rst.startSet(); - rst.initiate(); - - const adminDB = rst.getPrimary().getDB("admin"); - - // 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 dbName = "test"; - const collName = "transactions"; - const testDB = adminDB.getSiblingDB(dbName); - testDB.dropDatabase(); - assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}})); - - // Create two users. Alice will be given the 'internal' privilege. - assert.commandWorked( - adminDB.runCommand({createUser: "Alice", pwd: "pwd", roles: ["root", "__system"]})); - assert.commandWorked(adminDB.runCommand({createUser: "Mallory", pwd: "pwd", roles: ["root"]})); - adminDB.logout(); - - /** - * Test the prepareTransaction command with Alice who has the 'internal' privilege. - */ - assert.eq(1, adminDB.auth("Alice", "pwd")); - let lsid = assert.commandWorked(testDB.runCommand({startSession: 1})).id; - - // Start the transaction and insert a document. - assert.commandWorked(testDB.runCommand({ - insert: collName, - documents: [{_id: "alice"}], - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(0), - startTransaction: true, - autocommit: false - })); - - // Try to run prepareTransaction against the secondary. - assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Run prepareTransaction against the primary. - const prepareTimestamp = assert - .commandWorked(testDB.adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - })) - .prepareTimestamp; - const commitTimestamp = Timestamp(prepareTimestamp.getTime(), prepareTimestamp.getInc() + 1); - - // Commit the prepared transaction. - assert.commandWorked(testDB.adminCommand({ - commitTransaction: 1, - commitTimestamp: commitTimestamp, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(2), - autocommit: false - })); - - assert.eq(1, testDB[collName].find({_id: "alice"}).itcount()); - adminDB.logout(); - - /** - * Test the prepareTransaction command with Mallory who does not have the 'internal' privilege. - */ - assert.eq(1, adminDB.auth("Mallory", "pwd")); - - // Start the transaction and insert a document. - assert.commandWorked(testDB.runCommand({ - insert: collName, - documents: [{_id: "mallory"}], - lsid: lsid, - txnNumber: NumberLong(1), - stmtId: NumberInt(0), - startTransaction: true, - autocommit: false - })); - - // Try to run prepareTransaction against the secondary. - assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(1), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Run prepareTransaction against the primary. - assert.commandFailedWithCode(testDB.adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(1), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Cannot commit the transaction with 'commitTimestamp'. - assert.commandFailedWithCode(testDB.adminCommand({ - commitTransaction: 1, - commitTimestamp: Timestamp(0, 0), - lsid: lsid, - txnNumber: NumberLong(1), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.InvalidOptions); - - // The transaction should be aborted. - assert.commandFailedWithCode(testDB.adminCommand({ - commitTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(1), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.NoSuchTransaction); - - assert.eq(0, testDB[collName].find({_id: "mallory"}).itcount()); - adminDB.logout(); - - /** - * Test the prepareTransaction command with an unauthenticated user. - */ - - // Start the transaction and insert a document. - assert.commandFailedWithCode(testDB.runCommand({ - insert: collName, - documents: [{_id: "unauthenticated"}], - lsid: lsid, - txnNumber: NumberLong(2), - stmtId: NumberInt(0), - startTransaction: true, - autocommit: false - }), - ErrorCodes.Unauthorized); - - // Try to run prepareTransaction against the secondary. - assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(2), - stmtId: NumberInt(0), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Run prepareTransaction against the primary. - assert.commandFailedWithCode(testDB.adminCommand({ - prepareTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(2), - stmtId: NumberInt(0), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Cannot commit the transaction. - assert.commandFailedWithCode(testDB.adminCommand({ - commitTransaction: 1, - commitTimestamp: Timestamp(0, 0), - lsid: lsid, - txnNumber: NumberLong(2), - stmtId: NumberInt(0), - autocommit: false - }), - ErrorCodes.Unauthorized); - - assert.eq(1, adminDB.auth("Alice", "pwd")); - assert.eq(0, testDB[collName].find({_id: "unauthenticated"}).itcount()); - assert.commandWorked(testDB.runCommand({endSessions: [lsid]})); - adminDB.logout(); - - rst.stopSet(); +"use strict"; + +const rst = new ReplSetTest({nodes: 2, keyFile: "jstests/libs/key1"}); +rst.startSet(); +rst.initiate(); + +const adminDB = rst.getPrimary().getDB("admin"); + +// 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 dbName = "test"; +const collName = "transactions"; +const testDB = adminDB.getSiblingDB(dbName); +testDB.dropDatabase(); +assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}})); + +// Create two users. Alice will be given the 'internal' privilege. +assert.commandWorked( + adminDB.runCommand({createUser: "Alice", pwd: "pwd", roles: ["root", "__system"]})); +assert.commandWorked(adminDB.runCommand({createUser: "Mallory", pwd: "pwd", roles: ["root"]})); +adminDB.logout(); + +/** + * Test the prepareTransaction command with Alice who has the 'internal' privilege. + */ +assert.eq(1, adminDB.auth("Alice", "pwd")); +let lsid = assert.commandWorked(testDB.runCommand({startSession: 1})).id; + +// Start the transaction and insert a document. +assert.commandWorked(testDB.runCommand({ + insert: collName, + documents: [{_id: "alice"}], + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(0), + startTransaction: true, + autocommit: false +})); + +// Try to run prepareTransaction against the secondary. +assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Run prepareTransaction against the primary. +const prepareTimestamp = assert + .commandWorked(testDB.adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} + })) + .prepareTimestamp; +const commitTimestamp = Timestamp(prepareTimestamp.getTime(), prepareTimestamp.getInc() + 1); + +// Commit the prepared transaction. +assert.commandWorked(testDB.adminCommand({ + commitTransaction: 1, + commitTimestamp: commitTimestamp, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(2), + autocommit: false +})); + +assert.eq(1, testDB[collName].find({_id: "alice"}).itcount()); +adminDB.logout(); + +/** + * Test the prepareTransaction command with Mallory who does not have the 'internal' privilege. + */ +assert.eq(1, adminDB.auth("Mallory", "pwd")); + +// Start the transaction and insert a document. +assert.commandWorked(testDB.runCommand({ + insert: collName, + documents: [{_id: "mallory"}], + lsid: lsid, + txnNumber: NumberLong(1), + stmtId: NumberInt(0), + startTransaction: true, + autocommit: false +})); + +// Try to run prepareTransaction against the secondary. +assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(1), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Run prepareTransaction against the primary. +assert.commandFailedWithCode(testDB.adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(1), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Cannot commit the transaction with 'commitTimestamp'. +assert.commandFailedWithCode(testDB.adminCommand({ + commitTransaction: 1, + commitTimestamp: Timestamp(0, 0), + lsid: lsid, + txnNumber: NumberLong(1), + stmtId: NumberInt(1), + autocommit: false +}), + ErrorCodes.InvalidOptions); + +// The transaction should be aborted. +assert.commandFailedWithCode(testDB.adminCommand({ + commitTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(1), + stmtId: NumberInt(1), + autocommit: false +}), + ErrorCodes.NoSuchTransaction); + +assert.eq(0, testDB[collName].find({_id: "mallory"}).itcount()); +adminDB.logout(); + +/** + * Test the prepareTransaction command with an unauthenticated user. + */ + +// Start the transaction and insert a document. +assert.commandFailedWithCode(testDB.runCommand({ + insert: collName, + documents: [{_id: "unauthenticated"}], + lsid: lsid, + txnNumber: NumberLong(2), + stmtId: NumberInt(0), + startTransaction: true, + autocommit: false +}), + ErrorCodes.Unauthorized); + +// Try to run prepareTransaction against the secondary. +assert.commandFailedWithCode(rst.getSecondary().getDB(dbName).adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(2), + stmtId: NumberInt(0), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Run prepareTransaction against the primary. +assert.commandFailedWithCode(testDB.adminCommand({ + prepareTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(2), + stmtId: NumberInt(0), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Cannot commit the transaction. +assert.commandFailedWithCode(testDB.adminCommand({ + commitTransaction: 1, + commitTimestamp: Timestamp(0, 0), + lsid: lsid, + txnNumber: NumberLong(2), + stmtId: NumberInt(0), + autocommit: false +}), + ErrorCodes.Unauthorized); + +assert.eq(1, adminDB.auth("Alice", "pwd")); +assert.eq(0, testDB[collName].find({_id: "unauthenticated"}).itcount()); +assert.commandWorked(testDB.runCommand({endSessions: [lsid]})); +adminDB.logout(); + +rst.stopSet(); }()); diff --git a/jstests/auth/refresh_logical_session_cache_with_long_usernames.js b/jstests/auth/refresh_logical_session_cache_with_long_usernames.js index e584a1b8345..fb3cdb294d8 100644 --- a/jstests/auth/refresh_logical_session_cache_with_long_usernames.js +++ b/jstests/auth/refresh_logical_session_cache_with_long_usernames.js @@ -2,46 +2,49 @@ // usernames) (function() { - 'use strict'; +'use strict'; - // This test makes assertions about the number of sessions, which are not compatible with - // implicit sessions. - TestData.disableImplicitSessions = true; +// This test makes assertions about the number of sessions, which are not compatible with +// implicit sessions. +TestData.disableImplicitSessions = true; - const mongod = MongoRunner.runMongod({auth: ""}); +const mongod = MongoRunner.runMongod({auth: ""}); - const refresh = {refreshLogicalSessionCacheNow: 1}; - const startSession = {startSession: 1}; +const refresh = { + refreshLogicalSessionCacheNow: 1 +}; +const startSession = { + startSession: 1 +}; - const admin = mongod.getDB('admin'); - const db = mongod.getDB("test"); - const config = mongod.getDB("config"); +const admin = mongod.getDB('admin'); +const db = mongod.getDB("test"); +const config = mongod.getDB("config"); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); +admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +assert(admin.auth('admin', 'pass')); - const longUserName = "x".repeat(1000); +const longUserName = "x".repeat(1000); - // Create a user with a long name, so that the refresh records have a chance to blow out the - // 16MB limit, if all the sessions are flushed in one batch - db.createUser({user: longUserName, pwd: 'pass', roles: jsTest.basicUserRoles}); - admin.logout(); +// Create a user with a long name, so that the refresh records have a chance to blow out the +// 16MB limit, if all the sessions are flushed in one batch +db.createUser({user: longUserName, pwd: 'pass', roles: jsTest.basicUserRoles}); +admin.logout(); - assert(db.auth(longUserName, 'pass')); +assert(db.auth(longUserName, 'pass')); - // 20k * 1k = 20mb which is greater than 16mb - const numSessions = 20000; - for (var i = 0; i < numSessions; i++) { - assert.commandWorked(admin.runCommand(startSession), "unable to start session"); - } +// 20k * 1k = 20mb which is greater than 16mb +const numSessions = 20000; +for (var i = 0; i < numSessions; i++) { + assert.commandWorked(admin.runCommand(startSession), "unable to start session"); +} - assert.commandWorked(admin.runCommand(refresh), "failed to refresh"); +assert.commandWorked(admin.runCommand(refresh), "failed to refresh"); - // Make sure we actually flushed the sessions - assert.eq(numSessions, - config.system.sessions.aggregate([{'$listSessions': {}}, {'$count': "count"}]) - .next() - .count); +// Make sure we actually flushed the sessions +assert.eq( + numSessions, + config.system.sessions.aggregate([{'$listSessions': {}}, {'$count': "count"}]).next().count); - MongoRunner.stopMongod(mongod); +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/renameRestrictedCollections.js b/jstests/auth/renameRestrictedCollections.js index 1105da4eb3d..40169bef2d6 100644 --- a/jstests/auth/renameRestrictedCollections.js +++ b/jstests/auth/renameRestrictedCollections.js @@ -1,109 +1,113 @@ (function() { - 'use strict'; - - // SERVER-8623: Test that renameCollection can't be used to bypass auth checks on system - // namespaces - const conn = MongoRunner.runMongod({auth: ""}); - - const adminDB = conn.getDB("admin"); - const configDB = conn.getDB("config"); - const localDB = conn.getDB("local"); - const CodeUnauthorized = 13; - - const backdoorUserDoc = {user: 'backdoor', db: 'admin', pwd: 'hashed', roles: ['root']}; - - adminDB.createUser({user: 'userAdmin', pwd: 'password', roles: ['userAdminAnyDatabase']}); - - adminDB.auth('userAdmin', 'password'); - adminDB.createUser({user: 'readWriteAdmin', pwd: 'password', roles: ['readWriteAnyDatabase']}); - adminDB.createUser({ - user: 'readWriteAndUserAdmin', - pwd: 'password', - roles: ['readWriteAnyDatabase', 'userAdminAnyDatabase'] - }); - adminDB.createUser({user: 'root', pwd: 'password', roles: ['root']}); - adminDB.createUser({user: 'rootier', pwd: 'password', roles: ['__system']}); - adminDB.logout(); - - jsTestLog("Test that a readWrite user can't rename system.profile to something they can read"); - adminDB.auth('readWriteAdmin', 'password'); - var res = adminDB.system.profile.renameCollection("profile"); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - - jsTestLog("Test that a readWrite user can't rename system.users to something they can read"); - res = adminDB.system.users.renameCollection("users"); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - assert.eq(0, adminDB.users.count()); - - jsTestLog("Test that a readWrite user can't use renameCollection to override system.users"); - adminDB.users.insert(backdoorUserDoc); - res = adminDB.users.renameCollection("system.users", true); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - adminDB.users.drop(); - - jsTestLog("Test that a userAdmin can't rename system.users without readWrite"); - adminDB.logout(); - adminDB.auth('userAdmin', 'password'); - res = adminDB.system.users.renameCollection("users"); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - assert.eq(5, adminDB.system.users.count()); - - adminDB.auth('readWriteAndUserAdmin', 'password'); - assert.eq(0, adminDB.users.count()); - - jsTestLog("Test that even with userAdmin AND dbAdmin you CANNOT rename to/from system.users"); - res = adminDB.system.users.renameCollection("users"); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - assert.eq(5, adminDB.system.users.count()); - - adminDB.users.drop(); - adminDB.users.insert(backdoorUserDoc); - res = adminDB.users.renameCollection("system.users"); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - - assert.eq(null, adminDB.system.users.findOne({user: backdoorUserDoc.user})); - assert.neq(null, adminDB.system.users.findOne({user: 'userAdmin'})); - - adminDB.auth('rootier', 'password'); - - jsTestLog("Test that with __system you CAN rename to/from system.users"); - res = adminDB.system.users.renameCollection("users", true); - assert.eq(1, res.ok, tojson(res)); - - // Test permissions against the configDB and localDB - - // Start with test against inserting to and renaming collections in config and local - // as userAdminAnyDatabase. - assert.writeOK(configDB.test.insert({'a': 1})); - assert.commandWorked(configDB.test.renameCollection('test2')); - - assert.writeOK(localDB.test.insert({'a': 1})); - assert.commandWorked(localDB.test.renameCollection('test2')); - adminDB.logout(); - - // Test renaming collection in config with readWriteAnyDatabase - assert(adminDB.auth('readWriteAdmin', 'password')); - res = configDB.test2.insert({'b': 2}); - assert.writeError(res, 13, "not authorized on config to execute command"); - res = configDB.test2.renameCollection('test'); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - - // Test renaming collection in local with readWriteAnyDatabase - res = localDB.test2.insert({'b': 2}); - assert.writeError(res, 13, "not authorized on config to execute command"); - res = localDB.test2.renameCollection('test'); - assert.eq(0, res.ok); - assert.eq(CodeUnauthorized, res.code); - - // At this point, all the user documents are gone, so further activity may be unauthorized, - // depending on cluster configuration. So, this is the end of the test. - MongoRunner.stopMongod(conn, {user: 'userAdmin', pwd: 'password'}); - +'use strict'; + +// SERVER-8623: Test that renameCollection can't be used to bypass auth checks on system +// namespaces +const conn = MongoRunner.runMongod({auth: ""}); + +const adminDB = conn.getDB("admin"); +const configDB = conn.getDB("config"); +const localDB = conn.getDB("local"); +const CodeUnauthorized = 13; + +const backdoorUserDoc = { + user: 'backdoor', + db: 'admin', + pwd: 'hashed', + roles: ['root'] +}; + +adminDB.createUser({user: 'userAdmin', pwd: 'password', roles: ['userAdminAnyDatabase']}); + +adminDB.auth('userAdmin', 'password'); +adminDB.createUser({user: 'readWriteAdmin', pwd: 'password', roles: ['readWriteAnyDatabase']}); +adminDB.createUser({ + user: 'readWriteAndUserAdmin', + pwd: 'password', + roles: ['readWriteAnyDatabase', 'userAdminAnyDatabase'] +}); +adminDB.createUser({user: 'root', pwd: 'password', roles: ['root']}); +adminDB.createUser({user: 'rootier', pwd: 'password', roles: ['__system']}); +adminDB.logout(); + +jsTestLog("Test that a readWrite user can't rename system.profile to something they can read"); +adminDB.auth('readWriteAdmin', 'password'); +var res = adminDB.system.profile.renameCollection("profile"); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); + +jsTestLog("Test that a readWrite user can't rename system.users to something they can read"); +res = adminDB.system.users.renameCollection("users"); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); +assert.eq(0, adminDB.users.count()); + +jsTestLog("Test that a readWrite user can't use renameCollection to override system.users"); +adminDB.users.insert(backdoorUserDoc); +res = adminDB.users.renameCollection("system.users", true); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); +adminDB.users.drop(); + +jsTestLog("Test that a userAdmin can't rename system.users without readWrite"); +adminDB.logout(); +adminDB.auth('userAdmin', 'password'); +res = adminDB.system.users.renameCollection("users"); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); +assert.eq(5, adminDB.system.users.count()); + +adminDB.auth('readWriteAndUserAdmin', 'password'); +assert.eq(0, adminDB.users.count()); + +jsTestLog("Test that even with userAdmin AND dbAdmin you CANNOT rename to/from system.users"); +res = adminDB.system.users.renameCollection("users"); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); +assert.eq(5, adminDB.system.users.count()); + +adminDB.users.drop(); +adminDB.users.insert(backdoorUserDoc); +res = adminDB.users.renameCollection("system.users"); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); + +assert.eq(null, adminDB.system.users.findOne({user: backdoorUserDoc.user})); +assert.neq(null, adminDB.system.users.findOne({user: 'userAdmin'})); + +adminDB.auth('rootier', 'password'); + +jsTestLog("Test that with __system you CAN rename to/from system.users"); +res = adminDB.system.users.renameCollection("users", true); +assert.eq(1, res.ok, tojson(res)); + +// Test permissions against the configDB and localDB + +// Start with test against inserting to and renaming collections in config and local +// as userAdminAnyDatabase. +assert.writeOK(configDB.test.insert({'a': 1})); +assert.commandWorked(configDB.test.renameCollection('test2')); + +assert.writeOK(localDB.test.insert({'a': 1})); +assert.commandWorked(localDB.test.renameCollection('test2')); +adminDB.logout(); + +// Test renaming collection in config with readWriteAnyDatabase +assert(adminDB.auth('readWriteAdmin', 'password')); +res = configDB.test2.insert({'b': 2}); +assert.writeError(res, 13, "not authorized on config to execute command"); +res = configDB.test2.renameCollection('test'); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); + +// Test renaming collection in local with readWriteAnyDatabase +res = localDB.test2.insert({'b': 2}); +assert.writeError(res, 13, "not authorized on config to execute command"); +res = localDB.test2.renameCollection('test'); +assert.eq(0, res.ok); +assert.eq(CodeUnauthorized, res.code); + +// At this point, all the user documents are gone, so further activity may be unauthorized, +// depending on cluster configuration. So, this is the end of the test. +MongoRunner.stopMongod(conn, {user: 'userAdmin', pwd: 'password'}); })();
\ No newline at end of file diff --git a/jstests/auth/resource_pattern_matching.js b/jstests/auth/resource_pattern_matching.js index ca3c9b50195..ccefb8f51f5 100644 --- a/jstests/auth/resource_pattern_matching.js +++ b/jstests/auth/resource_pattern_matching.js @@ -13,12 +13,8 @@ function setup_users(granter) { admindb.runCommand({ createUser: "admin", pwd: "admin", - roles: [ - "userAdminAnyDatabase", - "dbAdminAnyDatabase", - "clusterAdmin", - "readWriteAnyDatabase" - ] + roles: + ["userAdminAnyDatabase", "dbAdminAnyDatabase", "clusterAdmin", "readWriteAnyDatabase"] }); admindb.auth("admin", "admin"); @@ -143,10 +139,10 @@ function run_tests(granter, verifier) { verifier, [{resource: {db: "a", collection: "a"}, actions: ["find"]}], { - "a.a": should_find, - "a.b": should_fail_find, - "b.a": should_fail_find, - "b.b": should_fail_find + "a.a": should_find, + "a.b": should_fail_find, + "b.a": should_fail_find, + "b.b": should_fail_find }); run_test( @@ -183,12 +179,12 @@ function run_tests(granter, verifier) { verifier, [{resource: {db: "$", collection: "cmd"}, actions: ["find"]}], { - "a.a": function(testdb, testcol) { - var r = testdb.stats(); + "a.a": function(testdb, testcol) { + var r = testdb.stats(); - if (r["ok"]) - throw("db.$.cmd shouldn't give a.stats()"); - } + if (r["ok"]) + throw ("db.$.cmd shouldn't give a.stats()"); + } }); run_test_bad_resource("empty_resource", granter, {}); @@ -202,26 +198,26 @@ function run_tests(granter, verifier) { granter, verifier, [ - {resource: {db: "a", collection: "a"}, actions: ["find"]}, - {resource: {db: "", collection: ""}, actions: ["insert"]} + {resource: {db: "a", collection: "a"}, actions: ["find"]}, + {resource: {db: "", collection: ""}, actions: ["insert"]} ], { - "a.a": function(testdb, testcol) { - should_insert(testdb, testcol); - should_find(testdb, testcol); - }, - "a.b": function(testdb, testcol) { - should_insert(testdb, testcol); - should_fail_find(testdb, testcol); - }, - "b.a": function(testdb, testcol) { - should_insert(testdb, testcol); - should_fail_find(testdb, testcol); - }, - "b.b": function(testdb, testcol) { - should_insert(testdb, testcol); - should_fail_find(testdb, testcol); - }, + "a.a": function(testdb, testcol) { + should_insert(testdb, testcol); + should_find(testdb, testcol); + }, + "a.b": function(testdb, testcol) { + should_insert(testdb, testcol); + should_fail_find(testdb, testcol); + }, + "b.a": function(testdb, testcol) { + should_insert(testdb, testcol); + should_fail_find(testdb, testcol); + }, + "b.b": function(testdb, testcol) { + should_insert(testdb, testcol); + should_fail_find(testdb, testcol); + }, }); } diff --git a/jstests/auth/role_management_commands_edge_cases.js b/jstests/auth/role_management_commands_edge_cases.js index 9dd774d5518..023f01df95e 100644 --- a/jstests/auth/role_management_commands_edge_cases.js +++ b/jstests/auth/role_management_commands_edge_cases.js @@ -92,10 +92,8 @@ function runTest(conn) { db.createRole({ role: 'role13', roles: [], - privileges: [{ - resource: {db: "test", collection: "foo", cluster: true}, - actions: ['find'] - }] + privileges: + [{resource: {db: "test", collection: "foo", cluster: true}, actions: ['find']}] }); }); assert.throws(function() { @@ -116,8 +114,7 @@ function runTest(conn) { db.createRole({ role: 'role16', roles: [], - privileges: - [{resource: {db: "test", collection: "foo"}, actions: ['fakeAction']}] + privileges: [{resource: {db: "test", collection: "foo"}, actions: ['fakeAction']}] }); }); @@ -233,7 +230,6 @@ function runTest(conn) { assert.throws(function() { db.revokeRolesFromRole("readWrite", ['read']); }); - })(); (function testGrantPrivilegesToRole() { diff --git a/jstests/auth/role_management_commands_lib.js b/jstests/auth/role_management_commands_lib.js index a4156a3be7e..a706899c6e7 100644 --- a/jstests/auth/role_management_commands_lib.js +++ b/jstests/auth/role_management_commands_lib.js @@ -194,8 +194,8 @@ function runAllRoleManagementCommandsTests(conn, writeConcern) { adminUserAdmin.grantPrivilegesToRole( 'adminRole', [ - {resource: {cluster: true}, actions: ['serverStatus']}, - {resource: {db: "", collection: ""}, actions: ['find']} + {resource: {cluster: true}, actions: ['serverStatus']}, + {resource: {db: "", collection: ""}, actions: ['find']} ], writeConcern); assert.doesNotThrow(function() { @@ -212,8 +212,8 @@ function runAllRoleManagementCommandsTests(conn, writeConcern) { testUserAdmin.grantPrivilegesToRole( 'testRole2', [ - {resource: {db: 'test', collection: ''}, actions: ['insert', 'update']}, - {resource: {db: 'test', collection: 'foo'}, actions: ['find']} + {resource: {db: 'test', collection: ''}, actions: ['insert', 'update']}, + {resource: {db: 'test', collection: 'foo'}, actions: ['find']} ], writeConcern); assert.doesNotThrow(function() { diff --git a/jstests/auth/role_management_commands_sharded_wc_1.js b/jstests/auth/role_management_commands_sharded_wc_1.js index 400e85b0029..9e7e3482d76 100644 --- a/jstests/auth/role_management_commands_sharded_wc_1.js +++ b/jstests/auth/role_management_commands_sharded_wc_1.js @@ -1,18 +1,18 @@ // @tags: [requires_sharding] (function() { - 'use strict'; +'use strict'; - load('jstests/auth/role_management_commands_lib.js'); +load('jstests/auth/role_management_commands_lib.js'); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest({ - shards: 2, - config: 3, - keyFile: 'jstests/libs/key1', - useHostname: false, - other: {shardAsReplicaSet: false} - }); - runAllRoleManagementCommandsTests(st.s, {w: 1}); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest({ + shards: 2, + config: 3, + keyFile: 'jstests/libs/key1', + useHostname: false, + other: {shardAsReplicaSet: false} +}); +runAllRoleManagementCommandsTests(st.s, {w: 1}); +st.stop(); })(); diff --git a/jstests/auth/role_management_commands_sharded_wc_majority.js b/jstests/auth/role_management_commands_sharded_wc_majority.js index 6bda9c5288a..155aa931feb 100644 --- a/jstests/auth/role_management_commands_sharded_wc_majority.js +++ b/jstests/auth/role_management_commands_sharded_wc_majority.js @@ -3,18 +3,18 @@ */ (function() { - 'use strict'; +'use strict'; - load('jstests/auth/role_management_commands_lib.js'); +load('jstests/auth/role_management_commands_lib.js'); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest({ - shards: 2, - config: 3, - keyFile: 'jstests/libs/key1', - useHostname: false, - other: {shardAsReplicaSet: false} - }); - runAllRoleManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest({ + shards: 2, + config: 3, + keyFile: 'jstests/libs/key1', + useHostname: false, + other: {shardAsReplicaSet: false} +}); +runAllRoleManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); +st.stop(); })(); diff --git a/jstests/auth/role_management_commands_standalone.js b/jstests/auth/role_management_commands_standalone.js index d35f2c30a3f..13d428c8afd 100644 --- a/jstests/auth/role_management_commands_standalone.js +++ b/jstests/auth/role_management_commands_standalone.js @@ -1,9 +1,9 @@ (function() { - 'use strict'; +'use strict'; - load('jstests/auth/role_management_commands_lib.js'); +load('jstests/auth/role_management_commands_lib.js'); - var conn = MongoRunner.runMongod({auth: '', useHostname: false}); - runAllRoleManagementCommandsTests(conn); - MongoRunner.stopMongod(conn); +var conn = MongoRunner.runMongod({auth: '', useHostname: false}); +runAllRoleManagementCommandsTests(conn); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/sasl_mechanism_discovery.js b/jstests/auth/sasl_mechanism_discovery.js index 0a2a05c2771..e64c8e3c545 100644 --- a/jstests/auth/sasl_mechanism_discovery.js +++ b/jstests/auth/sasl_mechanism_discovery.js @@ -1,80 +1,76 @@ // Tests that a client may discover a user's supported SASL mechanisms via isMaster. // @tags: [requires_sharding] (function() { - "use strict"; +"use strict"; - function runTest(conn) { - function checkMechs(userid, mechs) { - const res = - assert.commandWorked(db.runCommand({isMaster: 1, saslSupportedMechs: userid})); - assert.eq(mechs.sort(), res.saslSupportedMechs.sort(), tojson(res)); - } +function runTest(conn) { + function checkMechs(userid, mechs) { + const res = assert.commandWorked(db.runCommand({isMaster: 1, saslSupportedMechs: userid})); + assert.eq(mechs.sort(), res.saslSupportedMechs.sort(), tojson(res)); + } - var db = conn.getDB("admin"); - var externalDB = conn.getDB("$external"); + var db = conn.getDB("admin"); + var externalDB = conn.getDB("$external"); - assert.commandWorked(db.runCommand( - {createUser: "userAdmin", pwd: "userAdmin", roles: ["userAdminAnyDatabase"]})); - db.auth("userAdmin", "userAdmin"); + assert.commandWorked(db.runCommand( + {createUser: "userAdmin", pwd: "userAdmin", roles: ["userAdminAnyDatabase"]})); + db.auth("userAdmin", "userAdmin"); - // Check that unknown users do not interrupt isMaster - let res = - assert.commandWorked(db.runCommand({isMaster: 1, saslSupportedMechs: "test.bogus"})); - assert.eq(undefined, res.saslSupportedMechs); + // Check that unknown users do not interrupt isMaster + let res = assert.commandWorked(db.runCommand({isMaster: 1, saslSupportedMechs: "test.bogus"})); + assert.eq(undefined, res.saslSupportedMechs); - // Check that invalid usernames produce the correct error code - assert.commandFailedWithCode(db.runCommand({isMaster: 1, saslSupportedMechs: "bogus"}), - ErrorCodes.BadValue); + // Check that invalid usernames produce the correct error code + assert.commandFailedWithCode(db.runCommand({isMaster: 1, saslSupportedMechs: "bogus"}), + ErrorCodes.BadValue); - assert.commandWorked(db.runCommand({createUser: "user", pwd: "pwd", roles: []})); - assert.commandWorked(externalDB.runCommand({createUser: "user", roles: []})); + assert.commandWorked(db.runCommand({createUser: "user", pwd: "pwd", roles: []})); + assert.commandWorked(externalDB.runCommand({createUser: "user", roles: []})); - // Internal users should support scram methods. - checkMechs("admin.user", ["SCRAM-SHA-256", "SCRAM-SHA-1"]); + // Internal users should support scram methods. + checkMechs("admin.user", ["SCRAM-SHA-256", "SCRAM-SHA-1"]); - // External users on enterprise should support PLAIN, but not scram methods. - if (assert.commandWorked(db.runCommand({buildInfo: 1})).modules.includes("enterprise")) { - checkMechs("$external.user", ["PLAIN"]); - } else { - checkMechs("$external.user", []); - } + // External users on enterprise should support PLAIN, but not scram methods. + if (assert.commandWorked(db.runCommand({buildInfo: 1})).modules.includes("enterprise")) { + checkMechs("$external.user", ["PLAIN"]); + } else { + checkMechs("$external.user", []); + } - // Users with explicit mechs should only support those mechanisms - assert.commandWorked(db.runCommand( - {createUser: "256Only", pwd: "pwd", roles: [], mechanisms: ["SCRAM-SHA-256"]})); - checkMechs("admin.256Only", ["SCRAM-SHA-256"]); - assert.commandWorked(db.runCommand( - {createUser: "1Only", pwd: "pwd", roles: [], mechanisms: ["SCRAM-SHA-1"]})); - checkMechs("admin.1Only", ["SCRAM-SHA-1"]); + // Users with explicit mechs should only support those mechanisms + assert.commandWorked(db.runCommand( + {createUser: "256Only", pwd: "pwd", roles: [], mechanisms: ["SCRAM-SHA-256"]})); + checkMechs("admin.256Only", ["SCRAM-SHA-256"]); + assert.commandWorked( + db.runCommand({createUser: "1Only", pwd: "pwd", roles: [], mechanisms: ["SCRAM-SHA-1"]})); + checkMechs("admin.1Only", ["SCRAM-SHA-1"]); - // Users with normalized and unnormalized names do not conflict - assert.commandWorked(db.runCommand({createUser: "IX", pwd: "pwd", roles: []})); - checkMechs("admin.IX", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); - assert.commandWorked(db.runCommand({createUser: "\u2168", pwd: "pwd", roles: []})); - checkMechs("admin.\u2168", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); + // Users with normalized and unnormalized names do not conflict + assert.commandWorked(db.runCommand({createUser: "IX", pwd: "pwd", roles: []})); + checkMechs("admin.IX", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); + assert.commandWorked(db.runCommand({createUser: "\u2168", pwd: "pwd", roles: []})); + checkMechs("admin.\u2168", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); - // __system's mechanisms can be queried on local and admin if the server is in test mode - checkMechs("local.__system", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); - checkMechs("admin.__system", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); - } + // __system's mechanisms can be queried on local and admin if the server is in test mode + checkMechs("local.__system", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); + checkMechs("admin.__system", ["SCRAM-SHA-1", "SCRAM-SHA-256"]); +} - // Test standalone. - var m = MongoRunner.runMongod({ - keyFile: 'jstests/libs/key1', - setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256,PLAIN" - }); - runTest(m); - MongoRunner.stopMongod(m); +// Test standalone. +var m = MongoRunner.runMongod({ + keyFile: 'jstests/libs/key1', + setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256,PLAIN" +}); +runTest(m); +MongoRunner.stopMongod(m); - // Test mongos. - var st = new ShardingTest({ - keyFile: 'jstests/libs/key1', - shards: 0, - other: { - mongosOptions: - {setParameter: "authenticationMechanisms=PLAIN,SCRAM-SHA-256,SCRAM-SHA-1"} - } - }); - runTest(st.s0); - st.stop(); +// Test mongos. +var st = new ShardingTest({ + keyFile: 'jstests/libs/key1', + shards: 0, + other: + {mongosOptions: {setParameter: "authenticationMechanisms=PLAIN,SCRAM-SHA-256,SCRAM-SHA-1"}} +}); +runTest(st.s0); +st.stop(); })(); diff --git a/jstests/auth/scram-credentials-invalid.js b/jstests/auth/scram-credentials-invalid.js index c5553c31f26..282c5c06cc9 100644 --- a/jstests/auth/scram-credentials-invalid.js +++ b/jstests/auth/scram-credentials-invalid.js @@ -2,43 +2,40 @@ // user with invalid SCRAM-SHA-1 credentials fails gracefully. (function() { - 'use strict'; - - function runTest(mongod) { - assert(mongod); - const admin = mongod.getDB('admin'); - const test = mongod.getDB('test'); - - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - - test.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); - - // Give the test user an invalid set of SCRAM-SHA-1 credentials. - assert.eq(admin.system.users - .update({_id: "test.user"}, { - $set: { - "credentials.SCRAM-SHA-1": { - salt: "AAAA", - storedKey: "AAAA", - serverKey: "AAAA", - iterationCount: 10000 - } - } - }) - .nModified, - 1, - "Should have updated one document for user@test"); - admin.logout(); - - const error = assert.throws(function() { - test._authOrThrow({user: 'user', pwd: 'pass'}); - }); - - assert.eq(error, "Error: credential document SCRAM-SHA-1 failed validation"); - } - - const mongod = MongoRunner.runMongod({auth: "", useLogFiles: true}); - runTest(mongod); - MongoRunner.stopMongod(mongod); +'use strict'; + +function runTest(mongod) { + assert(mongod); + const admin = mongod.getDB('admin'); + const test = mongod.getDB('test'); + + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + + test.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); + + // Give the test user an invalid set of SCRAM-SHA-1 credentials. + assert.eq( + admin.system.users + .update({_id: "test.user"}, { + $set: { + "credentials.SCRAM-SHA-1": + {salt: "AAAA", storedKey: "AAAA", serverKey: "AAAA", iterationCount: 10000} + } + }) + .nModified, + 1, + "Should have updated one document for user@test"); + admin.logout(); + + const error = assert.throws(function() { + test._authOrThrow({user: 'user', pwd: 'pass'}); + }); + + assert.eq(error, "Error: credential document SCRAM-SHA-1 failed validation"); +} + +const mongod = MongoRunner.runMongod({auth: "", useLogFiles: true}); +runTest(mongod); +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/shell.js b/jstests/auth/shell.js index b3d391fd70e..0685798952c 100644 --- a/jstests/auth/shell.js +++ b/jstests/auth/shell.js @@ -1,19 +1,19 @@ // Authenticate to a mongod from the shell via command line. (function() { - 'use strict'; +'use strict'; - const port = allocatePort(); - const mongod = MongoRunner.runMongod({auth: '', port: port}); - const admin = mongod.getDB('admin'); +const port = allocatePort(); +const mongod = MongoRunner.runMongod({auth: '', port: port}); +const admin = mongod.getDB('admin'); - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - // Connect via shell round-trip in order to verify handling of mongodb:// uri with password. - const uri = 'mongodb://admin:pass@localhost:' + port + '/admin'; - // Be sure to actually do something requiring authentication. - const mongo = runMongoProgram('mongo', uri, '--eval', 'db.system.users.find({});'); - assert.eq(mongo, 0, "Failed connecting to mongod via shell+mongodb uri"); +// Connect via shell round-trip in order to verify handling of mongodb:// uri with password. +const uri = 'mongodb://admin:pass@localhost:' + port + '/admin'; +// Be sure to actually do something requiring authentication. +const mongo = runMongoProgram('mongo', uri, '--eval', 'db.system.users.find({});'); +assert.eq(mongo, 0, "Failed connecting to mongod via shell+mongodb uri"); - MongoRunner.stopMongod(mongod); +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/system_auth_scram_mechs.js b/jstests/auth/system_auth_scram_mechs.js index 7b6605a41c9..08934385d05 100644 --- a/jstests/auth/system_auth_scram_mechs.js +++ b/jstests/auth/system_auth_scram_mechs.js @@ -4,21 +4,21 @@ * @tags: [requires_replication] */ (function() { - 'use strict'; +'use strict'; - const keyfile = 'jstests/libs/key1'; - const keyfileContents = cat(keyfile).replace(/[\011-\015\040]/g, ''); - const rs = new ReplSetTest({nodes: 3, keyFile: keyfile}); - rs.startSet(); - rs.initiate(); - const db = rs.getPrimary().getDB("admin"); +const keyfile = 'jstests/libs/key1'; +const keyfileContents = cat(keyfile).replace(/[\011-\015\040]/g, ''); +const rs = new ReplSetTest({nodes: 3, keyFile: keyfile}); +rs.startSet(); +rs.initiate(); +const db = rs.getPrimary().getDB("admin"); - jsTestLog("Testing scram-sha-256"); - assert.eq(db.auth({mechanism: 'SCRAM-SHA-256', user: '__system', pwd: keyfileContents}), 1); - db.logout(); +jsTestLog("Testing scram-sha-256"); +assert.eq(db.auth({mechanism: 'SCRAM-SHA-256', user: '__system', pwd: keyfileContents}), 1); +db.logout(); - jsTestLog("Testing scram-sha-1"); - assert.eq(db.auth({mechanism: 'SCRAM-SHA-1', user: '__system', pwd: keyfileContents}), 1); +jsTestLog("Testing scram-sha-1"); +assert.eq(db.auth({mechanism: 'SCRAM-SHA-1', user: '__system', pwd: keyfileContents}), 1); - rs.stopSet(); +rs.stopSet(); })(); diff --git a/jstests/auth/system_roles_collMod.js b/jstests/auth/system_roles_collMod.js index c82a8d8b8b1..7b5f57567e0 100644 --- a/jstests/auth/system_roles_collMod.js +++ b/jstests/auth/system_roles_collMod.js @@ -1,24 +1,24 @@ // Verify custom roles still exist after noop collMod calls (function() { - 'use strict'; - print("START auth-system-roles-collMod.js"); - TestData.roleGraphInvalidationIsFatal = false; - var conn = MongoRunner.runMongod({}); - var db = conn.getDB("test"); +'use strict'; +print("START auth-system-roles-collMod.js"); +TestData.roleGraphInvalidationIsFatal = false; +var conn = MongoRunner.runMongod({}); +var db = conn.getDB("test"); - assert.commandWorked(db.runCommand( - {createRole: "role1", roles: [{role: "readWrite", db: "test"}], privileges: []})); - assert(db.runCommand({rolesInfo: "role1"}).roles[0].role === "role1"); +assert.commandWorked( + db.runCommand({createRole: "role1", roles: [{role: "readWrite", db: "test"}], privileges: []})); +assert(db.runCommand({rolesInfo: "role1"}).roles[0].role === "role1"); - // RoleGraph not invalidated after empty collMod - assert.commandWorked(db.adminCommand({collMod: "system.roles"})); - assert(db.runCommand({rolesInfo: "role1"}).roles[0].role === "role1"); +// RoleGraph not invalidated after empty collMod +assert.commandWorked(db.adminCommand({collMod: "system.roles"})); +assert(db.runCommand({rolesInfo: "role1"}).roles[0].role === "role1"); - // RoleGraph invalidated after non-empty collMod - assert.commandWorked(db.adminCommand({collMod: "system.roles", validationLevel: "off"})); - assert(db.runCommand({rolesInfo: "role1"}).roles.length === 0); +// RoleGraph invalidated after non-empty collMod +assert.commandWorked(db.adminCommand({collMod: "system.roles", validationLevel: "off"})); +assert(db.runCommand({rolesInfo: "role1"}).roles.length === 0); - print("SUCCESS auth-system-roles-collMod.js"); - MongoRunner.stopMongod(conn); +print("SUCCESS auth-system-roles-collMod.js"); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/system_user_exception.js b/jstests/auth/system_user_exception.js index 5955d629135..67814119541 100644 --- a/jstests/auth/system_user_exception.js +++ b/jstests/auth/system_user_exception.js @@ -1,21 +1,19 @@ // Test the special handling of the __system user // works when the SCRAM-SHA-1 pw auth mechanisms are disabled. (function() { - "use strict"; +"use strict"; - // Start mongod with no authentication mechanisms enabled - var m = MongoRunner.runMongod( - {keyFile: "jstests/libs/key1", setParameter: "authenticationMechanisms=PLAIN"}); +// Start mongod with no authentication mechanisms enabled +var m = MongoRunner.runMongod( + {keyFile: "jstests/libs/key1", setParameter: "authenticationMechanisms=PLAIN"}); - // Verify that it's possible to use SCRAM-SHA-1 to authenticate as the __system@local user - assert.eq( - 1, m.getDB("local").auth({user: "__system", pwd: "foopdedoop", mechanism: "SCRAM-SHA-1"})); +// Verify that it's possible to use SCRAM-SHA-1 to authenticate as the __system@local user +assert.eq(1, + m.getDB("local").auth({user: "__system", pwd: "foopdedoop", mechanism: "SCRAM-SHA-1"})); - // Verify that it is not possible to authenticate other users - m.getDB("test").runCommand( - {createUser: "guest", pwd: "guest", roles: jsTest.readOnlyUserRoles}); - assert.eq(0, m.getDB("test").auth({user: "guest", pwd: "guest", mechanism: "SCRAM-SHA-1"})); - - MongoRunner.stopMongod(m); +// Verify that it is not possible to authenticate other users +m.getDB("test").runCommand({createUser: "guest", pwd: "guest", roles: jsTest.readOnlyUserRoles}); +assert.eq(0, m.getDB("test").auth({user: "guest", pwd: "guest", mechanism: "SCRAM-SHA-1"})); +MongoRunner.stopMongod(m); })(); diff --git a/jstests/auth/system_user_privileges.js b/jstests/auth/system_user_privileges.js index 164ba9bd2e4..40619ba307c 100644 --- a/jstests/auth/system_user_privileges.js +++ b/jstests/auth/system_user_privileges.js @@ -12,91 +12,91 @@ (function() { - "use strict"; - - // Runs the "count" command on a database in a way that returns the result document, for easier - // inspection of the errmsg. - function runCountCommand(conn, dbName, collectionName) { - return conn.getDB(dbName).runCommand({count: collectionName}); - } - - // Asserts that on the given "conn", "dbName"."collectionName".count() fails as unauthorized. - function assertCountUnauthorized(conn, dbName, collectionName) { - assert.eq(runCountCommand(conn, dbName, collectionName).code, - 13, - "On " + dbName + "." + collectionName); - } - - var conn = MongoRunner.runMongod({auth: ""}); - - var admin = conn.getDB('admin'); - var test = conn.getDB('test'); - var local = conn.getDB('local'); - - // - // Preliminary set up. - // - admin.createUser({user: 'admin', pwd: 'a', roles: jsTest.adminUserRoles}); - admin.auth('admin', 'a'); - - // - // Add users named "__system" with no privileges on "test" and "admin", and make sure you can't - // add one on "local" - // - - test.createUser({user: '__system', pwd: 'a', roles: []}); - admin.createUser({user: '__system', pwd: 'a', roles: []}); - assert.throws(function() { - local.createUser({user: '__system', pwd: 'a', roles: []}); - }); - - // - // Add some data to count. - // - - admin.foo.insert({_id: 1}); - test.foo.insert({_id: 2}); - local.foo.insert({_id: 3}); - - admin.logout(); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - // - // Validate that you cannot even log in as __system@local with the supplied password; you _must_ - // use the password from the keyfile. - // - assert(!local.auth('__system', 'a')); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - // - // Validate that __system@test is not shadowed by the keyfile __system user. - // - test.auth('__system', 'a'); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - test.logout(); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - // - // Validate that __system@admin is not shadowed by the keyfile __system user. - // - admin.auth('__system', 'a'); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - admin.logout(); - assertCountUnauthorized(conn, "admin", "foo"); - assertCountUnauthorized(conn, "local", "foo"); - assertCountUnauthorized(conn, "test", "foo"); - - MongoRunner.stopMongod(conn, null, {user: 'admin', pwd: 'a'}); +"use strict"; + +// Runs the "count" command on a database in a way that returns the result document, for easier +// inspection of the errmsg. +function runCountCommand(conn, dbName, collectionName) { + return conn.getDB(dbName).runCommand({count: collectionName}); +} + +// Asserts that on the given "conn", "dbName"."collectionName".count() fails as unauthorized. +function assertCountUnauthorized(conn, dbName, collectionName) { + assert.eq(runCountCommand(conn, dbName, collectionName).code, + 13, + "On " + dbName + "." + collectionName); +} + +var conn = MongoRunner.runMongod({auth: ""}); + +var admin = conn.getDB('admin'); +var test = conn.getDB('test'); +var local = conn.getDB('local'); + +// +// Preliminary set up. +// +admin.createUser({user: 'admin', pwd: 'a', roles: jsTest.adminUserRoles}); +admin.auth('admin', 'a'); + +// +// Add users named "__system" with no privileges on "test" and "admin", and make sure you can't +// add one on "local" +// + +test.createUser({user: '__system', pwd: 'a', roles: []}); +admin.createUser({user: '__system', pwd: 'a', roles: []}); +assert.throws(function() { + local.createUser({user: '__system', pwd: 'a', roles: []}); +}); + +// +// Add some data to count. +// + +admin.foo.insert({_id: 1}); +test.foo.insert({_id: 2}); +local.foo.insert({_id: 3}); + +admin.logout(); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +// +// Validate that you cannot even log in as __system@local with the supplied password; you _must_ +// use the password from the keyfile. +// +assert(!local.auth('__system', 'a')); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +// +// Validate that __system@test is not shadowed by the keyfile __system user. +// +test.auth('__system', 'a'); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +test.logout(); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +// +// Validate that __system@admin is not shadowed by the keyfile __system user. +// +admin.auth('__system', 'a'); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +admin.logout(); +assertCountUnauthorized(conn, "admin", "foo"); +assertCountUnauthorized(conn, "local", "foo"); +assertCountUnauthorized(conn, "test", "foo"); + +MongoRunner.stopMongod(conn, null, {user: 'admin', pwd: 'a'}); })(); diff --git a/jstests/auth/transactions.js b/jstests/auth/transactions.js index 19e6526ab64..7037a78cd98 100644 --- a/jstests/auth/transactions.js +++ b/jstests/auth/transactions.js @@ -1,143 +1,141 @@ // Tests that users can only use transactions that they created. // @tags: [uses_transactions] (function() { - "use strict"; - - const rst = new ReplSetTest({nodes: 1, keyFile: "jstests/libs/key1"}); - rst.startSet(); - rst.initiate(); - - const adminDB = rst.getPrimary().getDB("admin"); - - // 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 dbName = "test"; - const collName = "transactions"; - const testDB = adminDB.getSiblingDB(dbName); - testDB.dropDatabase(); - assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}})); - - // 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(); - - // Alice starts a transaction. - assert.eq(1, testDB.auth("Alice", "pwd")); - const lsid = assert.commandWorked(testDB.runCommand({startSession: 1})).id; - assert.commandWorked(testDB.runCommand({ - insert: collName, - documents: [{_id: "alice-1"}], - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(0), - startTransaction: true, - autocommit: false - })); - testDB.logout(); - - // Mallory cannot continue the transaction. Using the same lsid for two different users creates - // two distinct sessions on the server. Mallory's session does not have an open transaction. - assert.eq(1, testDB.auth("Mallory", "pwd")); - assert.commandFailedWithCode(testDB.runCommand({ - insert: collName, - documents: [{_id: "mallory"}], - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.NoSuchTransaction); - - // Mallory cannot commit the transaction. - assert.commandFailedWithCode(adminDB.runCommand({ - commitTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.NoSuchTransaction); - - // Mallory cannot abort the transaction. - assert.commandFailedWithCode(adminDB.runCommand({ - abortTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.NoSuchTransaction); - testDB.logout(); - - // An unauthenticated user cannot continue the transaction. - assert.commandFailedWithCode(testDB.runCommand({ - insert: collName, - documents: [{_id: "unauthenticated"}], - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.Unauthorized); - - // An unauthenticated user cannot commit the transaction. - assert.commandFailedWithCode(adminDB.runCommand({ - commitTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // An unauthenticated user cannot abort the transaction. - assert.commandFailedWithCode(adminDB.runCommand({ - abortTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false, - writeConcern: {w: "majority"} - }), - ErrorCodes.Unauthorized); - - // Alice can continue the transaction. - assert.eq(1, testDB.auth("Alice", "pwd")); - assert.commandWorked(testDB.runCommand({ - insert: collName, - documents: [{_id: "alice-2"}], - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(1), - autocommit: false - })); - - // Alice can commit the transaction. - assert.commandWorked(adminDB.runCommand({ - commitTransaction: 1, - lsid: lsid, - txnNumber: NumberLong(0), - stmtId: NumberInt(2), - autocommit: false, - writeConcern: {w: "majority"} - })); - - // We do not see the writes from Mallory or the unauthenticated user. - assert.eq(1, testDB[collName].find({_id: "alice-1"}).itcount()); - assert.eq(1, testDB[collName].find({_id: "alice-2"}).itcount()); - assert.eq(0, testDB[collName].find({_id: "mallory"}).itcount()); - assert.eq(0, testDB[collName].find({_id: "unauthenticated"}).itcount()); - - assert.commandWorked(testDB.runCommand({endSessions: [lsid]})); - testDB.logout(); - rst.stopSet(); +"use strict"; + +const rst = new ReplSetTest({nodes: 1, keyFile: "jstests/libs/key1"}); +rst.startSet(); +rst.initiate(); + +const adminDB = rst.getPrimary().getDB("admin"); + +// 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 dbName = "test"; +const collName = "transactions"; +const testDB = adminDB.getSiblingDB(dbName); +testDB.dropDatabase(); +assert.commandWorked(testDB.runCommand({create: collName, writeConcern: {w: "majority"}})); + +// 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(); + +// Alice starts a transaction. +assert.eq(1, testDB.auth("Alice", "pwd")); +const lsid = assert.commandWorked(testDB.runCommand({startSession: 1})).id; +assert.commandWorked(testDB.runCommand({ + insert: collName, + documents: [{_id: "alice-1"}], + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(0), + startTransaction: true, + autocommit: false +})); +testDB.logout(); + +// Mallory cannot continue the transaction. Using the same lsid for two different users creates +// two distinct sessions on the server. Mallory's session does not have an open transaction. +assert.eq(1, testDB.auth("Mallory", "pwd")); +assert.commandFailedWithCode(testDB.runCommand({ + insert: collName, + documents: [{_id: "mallory"}], + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false +}), + ErrorCodes.NoSuchTransaction); + +// Mallory cannot commit the transaction. +assert.commandFailedWithCode(adminDB.runCommand({ + commitTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.NoSuchTransaction); + +// Mallory cannot abort the transaction. +assert.commandFailedWithCode(adminDB.runCommand({ + abortTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.NoSuchTransaction); +testDB.logout(); + +// An unauthenticated user cannot continue the transaction. +assert.commandFailedWithCode(testDB.runCommand({ + insert: collName, + documents: [{_id: "unauthenticated"}], + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false +}), + ErrorCodes.Unauthorized); + +// An unauthenticated user cannot commit the transaction. +assert.commandFailedWithCode(adminDB.runCommand({ + commitTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// An unauthenticated user cannot abort the transaction. +assert.commandFailedWithCode(adminDB.runCommand({ + abortTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false, + writeConcern: {w: "majority"} +}), + ErrorCodes.Unauthorized); + +// Alice can continue the transaction. +assert.eq(1, testDB.auth("Alice", "pwd")); +assert.commandWorked(testDB.runCommand({ + insert: collName, + documents: [{_id: "alice-2"}], + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(1), + autocommit: false +})); + +// Alice can commit the transaction. +assert.commandWorked(adminDB.runCommand({ + commitTransaction: 1, + lsid: lsid, + txnNumber: NumberLong(0), + stmtId: NumberInt(2), + autocommit: false, + writeConcern: {w: "majority"} +})); + +// We do not see the writes from Mallory or the unauthenticated user. +assert.eq(1, testDB[collName].find({_id: "alice-1"}).itcount()); +assert.eq(1, testDB[collName].find({_id: "alice-2"}).itcount()); +assert.eq(0, testDB[collName].find({_id: "mallory"}).itcount()); +assert.eq(0, testDB[collName].find({_id: "unauthenticated"}).itcount()); + +assert.commandWorked(testDB.runCommand({endSessions: [lsid]})); +testDB.logout(); +rst.stopSet(); }()); diff --git a/jstests/auth/upgrade_noauth_to_keyfile.js b/jstests/auth/upgrade_noauth_to_keyfile.js index 9bf2ec115e6..41eef5612c8 100644 --- a/jstests/auth/upgrade_noauth_to_keyfile.js +++ b/jstests/auth/upgrade_noauth_to_keyfile.js @@ -13,46 +13,46 @@ load('jstests/multiVersion/libs/multi_rs.js'); TestData.skipGossipingClusterTime = true; (function() { - 'use strict'; - var keyFilePath = 'jstests/libs/key1'; +'use strict'; +var keyFilePath = 'jstests/libs/key1'; - // Disable auth explicitly - var noAuthOptions = {noauth: ''}; +// Disable auth explicitly +var noAuthOptions = {noauth: ''}; - // Undefine the flags we're replacing, otherwise upgradeSet will keep old values. - var transitionToAuthOptions = - {noauth: undefined, clusterAuthMode: 'keyFile', keyFile: keyFilePath, transitionToAuth: ''}; - var keyFileOptions = { - clusterAuthMode: 'keyFile', - keyFile: keyFilePath, - transitionToAuth: undefined - }; +// Undefine the flags we're replacing, otherwise upgradeSet will keep old values. +var transitionToAuthOptions = + {noauth: undefined, clusterAuthMode: 'keyFile', keyFile: keyFilePath, transitionToAuth: ''}; +var keyFileOptions = { + clusterAuthMode: 'keyFile', + keyFile: keyFilePath, + transitionToAuth: undefined +}; - var rst = new ReplSetTest({name: 'noauthSet', nodes: 3, nodeOptions: noAuthOptions}); - rst.startSet(); - rst.initiate(); +var rst = new ReplSetTest({name: 'noauthSet', nodes: 3, nodeOptions: noAuthOptions}); +rst.startSet(); +rst.initiate(); - var rstConn1 = rst.getPrimary(); +var rstConn1 = rst.getPrimary(); - // Create a user to login as when auth is enabled later - rstConn1.getDB('admin').createUser({user: 'root', pwd: 'root', roles: ['root']}); +// Create a user to login as when auth is enabled later +rstConn1.getDB('admin').createUser({user: 'root', pwd: 'root', roles: ['root']}); - rstConn1.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); - assert.eq(1, rstConn1.getDB('test').a.count(), 'Error interacting with replSet'); +rstConn1.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); +assert.eq(1, rstConn1.getDB('test').a.count(), 'Error interacting with replSet'); - print('=== UPGRADE noauth -> transitionToAuth/keyFile ==='); - rst.upgradeSet(transitionToAuthOptions); - var rstConn2 = rst.getPrimary(); - rstConn2.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); - assert.eq(2, rstConn2.getDB('test').a.count(), 'Error interacting with replSet'); +print('=== UPGRADE noauth -> transitionToAuth/keyFile ==='); +rst.upgradeSet(transitionToAuthOptions); +var rstConn2 = rst.getPrimary(); +rstConn2.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); +assert.eq(2, rstConn2.getDB('test').a.count(), 'Error interacting with replSet'); - print('=== UPGRADE transitionToAuth/keyFile -> keyFile ==='); - rst.upgradeSet(keyFileOptions, 'root', 'root'); +print('=== UPGRADE transitionToAuth/keyFile -> keyFile ==='); +rst.upgradeSet(keyFileOptions, 'root', 'root'); - // upgradeSet leaves its connections logged in as root - var rstConn3 = rst.getPrimary(); - rstConn3.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); - assert.eq(3, rstConn3.getDB('test').a.count(), 'Error interacting with replSet'); +// upgradeSet leaves its connections logged in as root +var rstConn3 = rst.getPrimary(); +rstConn3.getDB('test').a.insert({a: 1, str: 'TESTTESTTEST'}); +assert.eq(3, rstConn3.getDB('test').a.count(), 'Error interacting with replSet'); - rst.stopSet(); +rst.stopSet(); }()); diff --git a/jstests/auth/upgrade_noauth_to_keyfile_with_sharding.js b/jstests/auth/upgrade_noauth_to_keyfile_with_sharding.js index 49d9e40c87c..148e9d1dbfc 100644 --- a/jstests/auth/upgrade_noauth_to_keyfile_with_sharding.js +++ b/jstests/auth/upgrade_noauth_to_keyfile_with_sharding.js @@ -5,29 +5,25 @@ load('jstests/ssl/libs/ssl_helpers.js'); (function() { - 'use strict'; +'use strict'; - // Disable auth explicitly - var noAuthOptions = {noauth: ''}; - var transitionToAuthOptions = { - clusterAuthMode: 'keyFile', - keyFile: KEYFILE, - transitionToAuth: '' - }; - var keyFileOptions = {clusterAuthMode: 'keyFile', keyFile: KEYFILE}; +// Disable auth explicitly +var noAuthOptions = {noauth: ''}; +var transitionToAuthOptions = {clusterAuthMode: 'keyFile', keyFile: KEYFILE, transitionToAuth: ''}; +var keyFileOptions = {clusterAuthMode: 'keyFile', keyFile: KEYFILE}; - print('=== Testing no-auth/transitionToAuth cluster ==='); - mixedShardTest(noAuthOptions, transitionToAuthOptions, true); - mixedShardTest(transitionToAuthOptions, noAuthOptions, true); +print('=== Testing no-auth/transitionToAuth cluster ==='); +mixedShardTest(noAuthOptions, transitionToAuthOptions, true); +mixedShardTest(transitionToAuthOptions, noAuthOptions, true); - print('=== Testing transitionToAuth/transitionToAuth cluster ==='); - mixedShardTest(transitionToAuthOptions, transitionToAuthOptions, true); +print('=== Testing transitionToAuth/transitionToAuth cluster ==='); +mixedShardTest(transitionToAuthOptions, transitionToAuthOptions, true); - print('=== Testing transitionToAuth/keyFile cluster ==='); - mixedShardTest(keyFileOptions, transitionToAuthOptions, true); - mixedShardTest(transitionToAuthOptions, keyFileOptions, true); +print('=== Testing transitionToAuth/keyFile cluster ==='); +mixedShardTest(keyFileOptions, transitionToAuthOptions, true); +mixedShardTest(transitionToAuthOptions, keyFileOptions, true); - print('=== Testing no-auth/keyFile cluster fails ==='); - mixedShardTest(noAuthOptions, keyFileOptions, false); - mixedShardTest(keyFileOptions, noAuthOptions, false); +print('=== Testing no-auth/keyFile cluster fails ==='); +mixedShardTest(noAuthOptions, keyFileOptions, false); +mixedShardTest(keyFileOptions, noAuthOptions, false); }()); diff --git a/jstests/auth/user_cache_doc_source.js b/jstests/auth/user_cache_doc_source.js index f56531fe580..3ffaee9b70e 100644 --- a/jstests/auth/user_cache_doc_source.js +++ b/jstests/auth/user_cache_doc_source.js @@ -1,47 +1,47 @@ // Tests the user cache document source (function() { - 'use strict'; - - var mongod = MongoRunner.runMongod({auth: ""}); - var db = mongod.getDB("admin"); - db.createUser({user: "root", pwd: "root", roles: ["userAdminAnyDatabase"]}); - db.auth("root", "root"); - db.createUser({user: "readOnlyUser", pwd: "foobar", roles: ["readAnyDatabase"]}); - var readUserCache = function() { - var ret = db.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); - print(tojson(ret)); - return ret; - }; - - const expectedOnlyRoot = [{username: "root", db: "admin", active: true}]; - assert.eq(expectedOnlyRoot, readUserCache()); - - /* This is broken because of SERVER-36384 - var newConn = new Mongo(mongod.name); - assert.eq(newConn.getDB("admin").auth("readOnlyUser", "foobar"), 1); - - const expectedBothActive = [ - { username: "root", db: "admin", active: true }, - { username: "readOnlyUser", db: "admin", active: true } - ]; - assert.eq(expectedBothActive, readUserCache()); - - newConn.close(); - */ - - var awaitShell = startParallelShell(function() { - assert.eq(db.getSisterDB("admin").auth("readOnlyUser", "foobar"), 1); - }, mongod.port); - - const expectedReadOnlyInactive = [ - {username: "readOnlyUser", db: "admin", active: false}, - {username: "root", db: "admin", active: true} - ]; - assert.soon(function() { - return friendlyEqual(expectedReadOnlyInactive, readUserCache()); - }); - - MongoRunner.stopMongod(mongod); - awaitShell({checkExitSuccess: false}); +'use strict'; + +var mongod = MongoRunner.runMongod({auth: ""}); +var db = mongod.getDB("admin"); +db.createUser({user: "root", pwd: "root", roles: ["userAdminAnyDatabase"]}); +db.auth("root", "root"); +db.createUser({user: "readOnlyUser", pwd: "foobar", roles: ["readAnyDatabase"]}); +var readUserCache = function() { + var ret = db.aggregate([{$listCachedAndActiveUsers: {}}]).toArray(); + print(tojson(ret)); + return ret; +}; + +const expectedOnlyRoot = [{username: "root", db: "admin", active: true}]; +assert.eq(expectedOnlyRoot, readUserCache()); + +/* This is broken because of SERVER-36384 +var newConn = new Mongo(mongod.name); +assert.eq(newConn.getDB("admin").auth("readOnlyUser", "foobar"), 1); + +const expectedBothActive = [ + { username: "root", db: "admin", active: true }, + { username: "readOnlyUser", db: "admin", active: true } +]; +assert.eq(expectedBothActive, readUserCache()); + +newConn.close(); +*/ + +var awaitShell = startParallelShell(function() { + assert.eq(db.getSisterDB("admin").auth("readOnlyUser", "foobar"), 1); +}, mongod.port); + +const expectedReadOnlyInactive = [ + {username: "readOnlyUser", db: "admin", active: false}, + {username: "root", db: "admin", active: true} +]; +assert.soon(function() { + return friendlyEqual(expectedReadOnlyInactive, readUserCache()); +}); + +MongoRunner.stopMongod(mongod); +awaitShell({checkExitSuccess: false}); })(); diff --git a/jstests/auth/user_defined_roles.js b/jstests/auth/user_defined_roles.js index 221c8c06e5a..a58d4ea52b6 100644 --- a/jstests/auth/user_defined_roles.js +++ b/jstests/auth/user_defined_roles.js @@ -100,10 +100,9 @@ function runTest(conn) { testDB.updateUser('testUser', {customData: {zipCode: 10036}}); }); assert.eq(null, testDB.getUser('testUser').customData); - testUserAdmin.grantPrivilegesToRole('testRole1', - [{ - resource: {db: 'test', collection: ''}, - actions: ['changeOwnPassword', 'changeOwnCustomData'] + testUserAdmin.grantPrivilegesToRole('testRole1', [{ + resource: {db: 'test', collection: ''}, + actions: ['changeOwnPassword', 'changeOwnCustomData'] }]); testDB.changeUserPassword('testUser', 'password'); assert(!testDB.auth('testUser', 'pwd')); diff --git a/jstests/auth/user_defined_roles_on_secondaries.js b/jstests/auth/user_defined_roles_on_secondaries.js index 69f768c3c15..47746e9cd56 100644 --- a/jstests/auth/user_defined_roles_on_secondaries.js +++ b/jstests/auth/user_defined_roles_on_secondaries.js @@ -37,197 +37,195 @@ (function() { - var name = 'user_defined_roles_on_secondaries'; - var m0, m1; - - function assertListContainsRole(list, role, msg) { - var i; - for (i = 0; i < list.length; ++i) { - if (list[i].role == role.role && list[i].db == role.db) - return; - } - doassert("Could not find value " + tojson(val) + " in " + tojson(list) + - (msg ? ": " + msg : "")); +var name = 'user_defined_roles_on_secondaries'; +var m0, m1; + +function assertListContainsRole(list, role, msg) { + var i; + for (i = 0; i < list.length; ++i) { + if (list[i].role == role.role && list[i].db == role.db) + return; } - - // - // Create a 1-node replicaset and add two roles, inheriting the built-in read role on db1. - // - // read - // / \ - // r1 r2 - // - var rstest = new ReplSetTest({name: name, nodes: 1, nodeOptions: {}}); - - rstest.startSet(); - rstest.initiate(); - - m0 = rstest.nodes[0]; - - m0.getDB("db1").createRole({ - role: "r1", - roles: ["read"], - privileges: [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] - }); - - m0.getDB("db1").createRole({ - role: "r2", - roles: ["read"], - privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] - }); - - // - // Add a second node to the set, and add a third role, dependent on the first two. - // - // read - // / \ - // r1 r2 - // \ / - // r3 - // - rstest.add(); - rstest.reInitiate(); - - // This write will have to wait on the initial sync to complete before progressing. - assert.soonNoExcept(() => { - assert.writeOK(rstest.getPrimary().getDB("db1")["aCollection"].insert( - {a: "afterSecondNodeAdded"}, {writeConcern: {w: 2, wtimeout: 60 * 1000}})); - return true; - }); - - rstest.getPrimary().getDB("db1").createRole({ - role: "r3", - roles: ["r1", "r2"], - privileges: [{resource: {db: "db1", collection: "log"}, actions: ["update"]}] - }, - {w: 2}); - - // Verify that both members of the set see the same role graph. - rstest.nodes.forEach(function(node) { - var role = node.getDB("db1").getRole("r3"); - assert.eq(2, role.roles.length, tojson(node)); - assertListContainsRole(role.roles, {role: "r1", db: "db1"}, node); - assertListContainsRole(role.roles, {role: "r2", db: "db1"}, node); - assert.eq(3, role.inheritedRoles.length, tojson(node)); - assertListContainsRole(role.inheritedRoles, {role: "r1", db: "db1"}, node); - assertListContainsRole(role.inheritedRoles, {role: "r2", db: "db1"}, node); - assertListContainsRole(role.inheritedRoles, {role: "read", db: "db1"}, node); - }); - - // Verify that updating roles propagates. - rstest.getPrimary().getDB("db1").revokeRolesFromRole("r1", ["read"], {w: 2}); - rstest.getPrimary().getDB("db1").grantRolesToRole("r1", ["dbAdmin"], {w: 2}); - rstest.nodes.forEach(function(node) { - var role = node.getDB("db1").getRole("r1"); - assert.eq(1, role.roles.length, tojson(node)); - assertListContainsRole(role.roles, {role: "dbAdmin", db: "db1"}); - }); - - // Verify that dropping roles propagates. - rstest.getPrimary().getDB("db1").dropRole("r2", {w: 2}); - rstest.nodes.forEach(function(node) { - assert.eq(null, node.getDB("db1").getRole("r2")); - var role = node.getDB("db1").getRole("r3"); - assert.eq(1, role.roles.length, tojson(node)); - assertListContainsRole(role.roles, {role: "r1", db: "db1"}, node); - assert.eq(2, role.inheritedRoles.length, tojson(node)); - assertListContainsRole(role.inheritedRoles, {role: "r1", db: "db1"}, node); - assertListContainsRole(role.inheritedRoles, {role: "dbAdmin", db: "db1"}, node); - }); - - // Verify that applyOps commands propagate. - // NOTE: This section of the test depends on the oplog and roles schemas. - assert.commandWorked(rstest.getPrimary().getDB("admin").runCommand({ - applyOps: [ - {op: "c", ns: "admin.$cmd", o: {create: "system.roles"}}, - { - op: "i", - ns: "admin.system.roles", - o: { - _id: "db1.s1", - role: "s1", - db: "db1", - roles: [{role: "read", db: "db1"}], - privileges: - [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] - } - }, - { - op: "i", - ns: "admin.system.roles", - o: { - _id: "db1.s2", - role: "s2", - db: "db1", - roles: [{role: "read", db: "db1"}], - privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] - } - }, - {op: "c", ns: "admin.$cmd", o: {drop: "system.roles"}}, - {op: "c", ns: "admin.$cmd", o: {create: "system.roles"}}, - { - op: "i", - ns: "admin.system.roles", - o: { - _id: "db1.t1", - role: "t1", - db: "db1", - roles: [{role: "read", db: "db1"}], - privileges: - [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] - } - }, - { - op: "i", - ns: "admin.system.roles", - o: { - _id: "db1.t2", - role: "t2", - db: "db1", - roles: [], - privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] - } - }, - { - op: "i", - ns: "admin.system.roles", - o: { - _id: "db1.t3", - role: "t3", - db: "db1", - roles: [{role: "t1", db: "db1"}, {role: "t2", db: "db1"}], - privileges: [] - } - }, - { - op: "u", - ns: "admin.system.roles", - o: {$set: {roles: [{role: "readWrite", db: "db1"}]}}, - o2: {_id: "db1.t2"} + doassert("Could not find value " + tojson(val) + " in " + tojson(list) + + (msg ? ": " + msg : "")); +} + +// +// Create a 1-node replicaset and add two roles, inheriting the built-in read role on db1. +// +// read +// / \ +// r1 r2 +// +var rstest = new ReplSetTest({name: name, nodes: 1, nodeOptions: {}}); + +rstest.startSet(); +rstest.initiate(); + +m0 = rstest.nodes[0]; + +m0.getDB("db1").createRole({ + role: "r1", + roles: ["read"], + privileges: [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] +}); + +m0.getDB("db1").createRole({ + role: "r2", + roles: ["read"], + privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] +}); + +// +// Add a second node to the set, and add a third role, dependent on the first two. +// +// read +// / \ +// r1 r2 +// \ / +// r3 +// +rstest.add(); +rstest.reInitiate(); + +// This write will have to wait on the initial sync to complete before progressing. +assert.soonNoExcept(() => { + assert.writeOK(rstest.getPrimary().getDB("db1")["aCollection"].insert( + {a: "afterSecondNodeAdded"}, {writeConcern: {w: 2, wtimeout: 60 * 1000}})); + return true; +}); + +rstest.getPrimary().getDB("db1").createRole({ + role: "r3", + roles: ["r1", "r2"], + privileges: [{resource: {db: "db1", collection: "log"}, actions: ["update"]}] +}, + {w: 2}); + +// Verify that both members of the set see the same role graph. +rstest.nodes.forEach(function(node) { + var role = node.getDB("db1").getRole("r3"); + assert.eq(2, role.roles.length, tojson(node)); + assertListContainsRole(role.roles, {role: "r1", db: "db1"}, node); + assertListContainsRole(role.roles, {role: "r2", db: "db1"}, node); + assert.eq(3, role.inheritedRoles.length, tojson(node)); + assertListContainsRole(role.inheritedRoles, {role: "r1", db: "db1"}, node); + assertListContainsRole(role.inheritedRoles, {role: "r2", db: "db1"}, node); + assertListContainsRole(role.inheritedRoles, {role: "read", db: "db1"}, node); +}); + +// Verify that updating roles propagates. +rstest.getPrimary().getDB("db1").revokeRolesFromRole("r1", ["read"], {w: 2}); +rstest.getPrimary().getDB("db1").grantRolesToRole("r1", ["dbAdmin"], {w: 2}); +rstest.nodes.forEach(function(node) { + var role = node.getDB("db1").getRole("r1"); + assert.eq(1, role.roles.length, tojson(node)); + assertListContainsRole(role.roles, {role: "dbAdmin", db: "db1"}); +}); + +// Verify that dropping roles propagates. +rstest.getPrimary().getDB("db1").dropRole("r2", {w: 2}); +rstest.nodes.forEach(function(node) { + assert.eq(null, node.getDB("db1").getRole("r2")); + var role = node.getDB("db1").getRole("r3"); + assert.eq(1, role.roles.length, tojson(node)); + assertListContainsRole(role.roles, {role: "r1", db: "db1"}, node); + assert.eq(2, role.inheritedRoles.length, tojson(node)); + assertListContainsRole(role.inheritedRoles, {role: "r1", db: "db1"}, node); + assertListContainsRole(role.inheritedRoles, {role: "dbAdmin", db: "db1"}, node); +}); + +// Verify that applyOps commands propagate. +// NOTE: This section of the test depends on the oplog and roles schemas. +assert.commandWorked(rstest.getPrimary().getDB("admin").runCommand({ + applyOps: [ + {op: "c", ns: "admin.$cmd", o: {create: "system.roles"}}, + { + op: "i", + ns: "admin.system.roles", + o: { + _id: "db1.s1", + role: "s1", + db: "db1", + roles: [{role: "read", db: "db1"}], + privileges: [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] + } + }, + { + op: "i", + ns: "admin.system.roles", + o: { + _id: "db1.s2", + role: "s2", + db: "db1", + roles: [{role: "read", db: "db1"}], + privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] + } + }, + {op: "c", ns: "admin.$cmd", o: {drop: "system.roles"}}, + {op: "c", ns: "admin.$cmd", o: {create: "system.roles"}}, + { + op: "i", + ns: "admin.system.roles", + o: { + _id: "db1.t1", + role: "t1", + db: "db1", + roles: [{role: "read", db: "db1"}], + privileges: [{resource: {db: "db1", collection: "system.users"}, actions: ["find"]}] } - ] - })); - - assert.commandWorked(rstest.getPrimary().getDB("admin").getLastErrorObj(2)); - rstest.nodes.forEach(function(node) { - var role = node.getDB("db1").getRole("t1"); - assert.eq(1, role.roles.length, tojson(node)); - assertListContainsRole(role.roles, {role: "read", db: "db1"}, node); - - var role = node.getDB("db1").getRole("t2"); - assert.eq(1, role.roles.length, tojson(node)); - assertListContainsRole(role.roles, {role: "readWrite", db: "db1"}, node); - }); - - // Verify that irrelevant index creation doesn't impair graph resolution - assert.commandWorked(rstest.getPrimary().getDB("admin").col.save({data: 5})); - assert.commandWorked(rstest.getPrimary().getDB("admin").runCommand( - {createIndexes: "col", indexes: [{key: {data: 1}, name: "testIndex"}]})); - rstest.awaitReplication(); - rstest.nodes.forEach(function(node) { - var role = node.getDB("db1").getRole("t3"); - assert.eq(4, role.inheritedRoles.length, tojson(node)); - }); - - rstest.stopSet(); + }, + { + op: "i", + ns: "admin.system.roles", + o: { + _id: "db1.t2", + role: "t2", + db: "db1", + roles: [], + privileges: [{resource: {db: "db1", collection: "log"}, actions: ["insert"]}] + } + }, + { + op: "i", + ns: "admin.system.roles", + o: { + _id: "db1.t3", + role: "t3", + db: "db1", + roles: [{role: "t1", db: "db1"}, {role: "t2", db: "db1"}], + privileges: [] + } + }, + { + op: "u", + ns: "admin.system.roles", + o: {$set: {roles: [{role: "readWrite", db: "db1"}]}}, + o2: {_id: "db1.t2"} + } + ] +})); + +assert.commandWorked(rstest.getPrimary().getDB("admin").getLastErrorObj(2)); +rstest.nodes.forEach(function(node) { + var role = node.getDB("db1").getRole("t1"); + assert.eq(1, role.roles.length, tojson(node)); + assertListContainsRole(role.roles, {role: "read", db: "db1"}, node); + + var role = node.getDB("db1").getRole("t2"); + assert.eq(1, role.roles.length, tojson(node)); + assertListContainsRole(role.roles, {role: "readWrite", db: "db1"}, node); +}); + +// Verify that irrelevant index creation doesn't impair graph resolution +assert.commandWorked(rstest.getPrimary().getDB("admin").col.save({data: 5})); +assert.commandWorked(rstest.getPrimary().getDB("admin").runCommand( + {createIndexes: "col", indexes: [{key: {data: 1}, name: "testIndex"}]})); +rstest.awaitReplication(); +rstest.nodes.forEach(function(node) { + var role = node.getDB("db1").getRole("t3"); + assert.eq(4, role.inheritedRoles.length, tojson(node)); +}); + +rstest.stopSet(); }()); diff --git a/jstests/auth/user_management_commands_edge_cases.js b/jstests/auth/user_management_commands_edge_cases.js index f8447ddd7c8..d197d0105b2 100644 --- a/jstests/auth/user_management_commands_edge_cases.js +++ b/jstests/auth/user_management_commands_edge_cases.js @@ -257,7 +257,6 @@ function runTest(conn) { assert.throws(function() { db.getUser(['user1']); }); - })(); (function testDropUser() { diff --git a/jstests/auth/user_management_commands_lib.js b/jstests/auth/user_management_commands_lib.js index f05987c2b1d..3bea79ab955 100644 --- a/jstests/auth/user_management_commands_lib.js +++ b/jstests/auth/user_management_commands_lib.js @@ -118,11 +118,11 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { testUserAdmin.grantRolesToUser('spencer', [ - 'readWrite', - 'dbAdmin', - {role: 'readWrite', db: 'test'}, - {role: 'testRole', db: 'test'}, - 'readWrite' + 'readWrite', + 'dbAdmin', + {role: 'readWrite', db: 'test'}, + {role: 'testRole', db: 'test'}, + 'readWrite' ], writeConcern); @@ -142,9 +142,9 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { testUserAdmin.revokeRolesFromUser( 'spencer', [ - 'readWrite', - {role: 'dbAdmin', db: 'test2'}, // role user doesnt have - "testRole" + 'readWrite', + {role: 'dbAdmin', db: 'test2'}, // role user doesnt have + "testRole" ], writeConcern); @@ -169,7 +169,6 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { db.getRole('testRole'); }); assert.commandFailedWithCode(db.adminCommand('connPoolSync'), ErrorCodes.Unauthorized); - })(); (function testUsersInfo() { diff --git a/jstests/auth/user_management_commands_mechanisms.js b/jstests/auth/user_management_commands_mechanisms.js index f0d8a2dbd12..98c806f194b 100644 --- a/jstests/auth/user_management_commands_mechanisms.js +++ b/jstests/auth/user_management_commands_mechanisms.js @@ -2,227 +2,215 @@ // @tags: [requires_persistence] (function() { - 'use strict'; - - let mongod = MongoRunner.runMongod( - {auth: "", setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256,PLAIN"}); - assert(mongod); - const admin = mongod.getDB('admin'); - const test = mongod.getDB('test'); - - function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) { - function checkCredentialRecord(creds, hashLen, saltLen, itCount) { - assert.eq(creds.iterationCount, itCount); - assert.eq(creds.salt.length, saltLen); - assert.eq(creds.storedKey.length, hashLen); - assert.eq(creds.serverKey.length, hashLen); - } - function checkLogin(mech, digestOK, nodigestOK) { - assert(test.auth({user: userid, pwd: passwd, mechanism: mech})); +'use strict'; + +let mongod = MongoRunner.runMongod( + {auth: "", setParameter: "authenticationMechanisms=SCRAM-SHA-1,SCRAM-SHA-256,PLAIN"}); +assert(mongod); +const admin = mongod.getDB('admin'); +const test = mongod.getDB('test'); + +function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) { + function checkCredentialRecord(creds, hashLen, saltLen, itCount) { + assert.eq(creds.iterationCount, itCount); + assert.eq(creds.salt.length, saltLen); + assert.eq(creds.storedKey.length, hashLen); + assert.eq(creds.serverKey.length, hashLen); + } + function checkLogin(mech, digestOK, nodigestOK) { + assert(test.auth({user: userid, pwd: passwd, mechanism: mech})); + test.logout(); + assert.eq(digestOK, + test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: true})); + if (digestOK) { test.logout(); - assert.eq( - digestOK, - test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: true})); - if (digestOK) { - test.logout(); - } - assert.eq( - nodigestOK, - test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: false})); - if (nodigestOK) { - test.logout(); - } } - - const user = admin.system.users.findOne({_id: ('test.' + userid)}); - assert.eq(user.credentials.hasOwnProperty('SCRAM-SHA-1'), haveSCRAMSHA1); - assert.eq(user.credentials.hasOwnProperty('SCRAM-SHA-256'), haveSCRAMSHA256); - - // usersInfo contains correct mechanisms for the user - const userInfo = assert.commandWorked(test.runCommand({usersInfo: userid})); - assert(Array.isArray(userInfo.users[0].mechanisms)); - assert.eq(userInfo.users[0].mechanisms.includes('SCRAM-SHA-1'), haveSCRAMSHA1); - assert.eq(userInfo.users[0].mechanisms.includes('SCRAM-SHA-256'), haveSCRAMSHA256); - - // usersInfo with showCredentials shows correct mechanisms and credentials - const userInfoWithCredentials = - assert.commandWorked(test.runCommand({usersInfo: userid, showCredentials: true})); - print(tojson(userInfoWithCredentials)); - assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty('SCRAM-SHA-1'), - haveSCRAMSHA1); - assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty('SCRAM-SHA-256'), - haveSCRAMSHA256); - assert(Array.isArray(userInfoWithCredentials.users[0].mechanisms)); - assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-1'), - haveSCRAMSHA1); - assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-256'), - haveSCRAMSHA256); - - if (haveSCRAMSHA1) { - checkCredentialRecord(user.credentials['SCRAM-SHA-1'], 28, 24, 10000); - checkLogin('SCRAM-SHA-1', true, false); - checkLogin('PLAIN', false, true); - } - if (haveSCRAMSHA256) { - checkCredentialRecord(user.credentials['SCRAM-SHA-256'], 44, 40, 15000); - checkLogin('SCRAM-SHA-256', false, true); - checkLogin('PLAIN', false, true); + assert.eq(nodigestOK, + test.auth({user: userid, pwd: passwd, mechanism: mech, digestPassword: false})); + if (nodigestOK) { + test.logout(); } } - admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(admin.auth('admin', 'pass')); - - // Unknown mechanism. - assert.throws(function() { - test.createUser({ - user: 'shalala', - pwd: 'pass', - roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-1', 'SCRAM-SHA-LA-LA'], - }); - }); - - // By default, users are created with both SCRAM variants. - test.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); - checkUser('user', 'pass', true, true); + const user = admin.system.users.findOne({_id: ('test.' + userid)}); + assert.eq(user.credentials.hasOwnProperty('SCRAM-SHA-1'), haveSCRAMSHA1); + assert.eq(user.credentials.hasOwnProperty('SCRAM-SHA-256'), haveSCRAMSHA256); + + // usersInfo contains correct mechanisms for the user + const userInfo = assert.commandWorked(test.runCommand({usersInfo: userid})); + assert(Array.isArray(userInfo.users[0].mechanisms)); + assert.eq(userInfo.users[0].mechanisms.includes('SCRAM-SHA-1'), haveSCRAMSHA1); + assert.eq(userInfo.users[0].mechanisms.includes('SCRAM-SHA-256'), haveSCRAMSHA256); + + // usersInfo with showCredentials shows correct mechanisms and credentials + const userInfoWithCredentials = + assert.commandWorked(test.runCommand({usersInfo: userid, showCredentials: true})); + print(tojson(userInfoWithCredentials)); + assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty('SCRAM-SHA-1'), + haveSCRAMSHA1); + assert.eq(userInfoWithCredentials.users[0].credentials.hasOwnProperty('SCRAM-SHA-256'), + haveSCRAMSHA256); + assert(Array.isArray(userInfoWithCredentials.users[0].mechanisms)); + assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-1'), haveSCRAMSHA1); + assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-256'), + haveSCRAMSHA256); + + if (haveSCRAMSHA1) { + checkCredentialRecord(user.credentials['SCRAM-SHA-1'], 28, 24, 10000); + checkLogin('SCRAM-SHA-1', true, false); + checkLogin('PLAIN', false, true); + } + if (haveSCRAMSHA256) { + checkCredentialRecord(user.credentials['SCRAM-SHA-256'], 44, 40, 15000); + checkLogin('SCRAM-SHA-256', false, true); + checkLogin('PLAIN', false, true); + } +} - // Request SHA1 only. - test.createUser( - {user: 'sha1user', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); - checkUser('sha1user', 'pass', true, false); +admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +assert(admin.auth('admin', 'pass')); - // Request SHA256 only. +// Unknown mechanism. +assert.throws(function() { test.createUser({ - user: 'sha256user', + user: 'shalala', pwd: 'pass', roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-256'] + mechanisms: ['SCRAM-SHA-1', 'SCRAM-SHA-LA-LA'], }); - checkUser('sha256user', 'pass', false, true); +}); - // Fail passing an empty mechanisms field. - assert.throws(function() { - test.createUser( - {user: 'userNoMech', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: []}); - }); +// By default, users are created with both SCRAM variants. +test.createUser({user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); +checkUser('user', 'pass', true, true); - // Repeat above, but request client-side digesting. - // Only the SCRAM-SHA-1 exclusive version should succeed. +// Request SHA1 only. +test.createUser( + {user: 'sha1user', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); +checkUser('sha1user', 'pass', true, false); - assert.throws(function() { - test.createUser({ - user: 'user2', - pwd: 'pass', - roles: jsTest.basicUserRoles, - passwordDisgestor: 'client' - }); - }); +// Request SHA256 only. +test.createUser( + {user: 'sha256user', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-256']}); +checkUser('sha256user', 'pass', false, true); + +// Fail passing an empty mechanisms field. +assert.throws(function() { + test.createUser( + {user: 'userNoMech', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: []}); +}); + +// Repeat above, but request client-side digesting. +// Only the SCRAM-SHA-1 exclusive version should succeed. +assert.throws(function() { + test.createUser( + {user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles, passwordDisgestor: 'client'}); +}); + +test.createUser({ + user: 'sha1user2', + pwd: 'pass', + roles: jsTest.basicUserRoles, + mechanisms: ['SCRAM-SHA-1'], + passwordDigestor: 'client' +}); +checkUser('sha1user2', 'pass', true, false); + +assert.throws(function() { test.createUser({ - user: 'sha1user2', + user: 'sha256user2', pwd: 'pass', roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-1'], + mechanisms: ['SCRAM-SHA-256'], passwordDigestor: 'client' }); - checkUser('sha1user2', 'pass', true, false); - - assert.throws(function() { - test.createUser({ - user: 'sha256user2', - pwd: 'pass', - roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-256'], - passwordDigestor: 'client' - }); - }); - - // Update original 1/256 user to just sha-1. - test.updateUser('user', {pwd: 'pass1', mechanisms: ['SCRAM-SHA-1']}); - checkUser('user', 'pass1', true, false); - - // Then flip to 256-only - test.updateUser('user', {pwd: 'pass256', mechanisms: ['SCRAM-SHA-256']}); - checkUser('user', 'pass256', false, true); - - // And back to (default) all. - test.updateUser('user', {pwd: 'passAll'}); - checkUser('user', 'passAll', true, true); - - // Trim out mechanisms without changing password. - test.updateUser('user', {mechanisms: ['SCRAM-SHA-256']}); - checkUser('user', 'passAll', false, true); - - // Fail when mechanisms is not a subset of the current user. - assert.throws(function() { - test.updateUser('user', {mechanisms: ['SCRAM-SHA-1']}); - }); - - // Fail when passing an empty mechanisms field. - assert.throws(function() { - test.updateUser('user', {pwd: 'passEmpty', mechanisms: []}); - }); - - // Succeed if we're using SHA-1 only. - test.createUser( - {user: "\u2168", pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); - checkUser("\u2168", 'pass', true, false); - - // Demonstrate that usersInfo returns all users with mechanisms lists - const allUsersInfo = assert.commandWorked(test.runCommand({usersInfo: 1})); - allUsersInfo.users.forEach(function(userObj) { - assert(Array.isArray(userObj.mechanisms)); - }); - - // Demonstrate that usersInfo can return all users with credentials - const allUsersInfoWithCredentials = - assert.commandWorked(test.runCommand({usersInfo: 1, showCredentials: true})); - allUsersInfoWithCredentials.users.forEach(function(userObj) { - assert(userObj.credentials !== undefined); - assert(!Array.isArray(userObj.credentials)); - assert(userObj.mechanisms !== undefined); - assert(Array.isArray(userObj.mechanisms)); - }); - - // Demonstrate that usersInfo can find SCRAM-SHA-1 users - const allSCRAMSHA1UsersInfo = - assert.commandWorked(test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-1"}})); - let foundUsers = []; - allSCRAMSHA1UsersInfo.users.forEach(function(userObj) { - foundUsers.push(userObj.user); - }); - assert.eq(["sha1user", "sha1user2", "\u2168"], foundUsers); - - // Demonstrate that usersInfo can find SCRAM-SHA-256 users - const allSCRAMSHA256UsersInfo = assert.commandWorked( - test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-256"}})); - foundUsers = []; - allSCRAMSHA256UsersInfo.users.forEach(function(userObj) { - foundUsers.push(userObj.user); - }); - assert.eq(["sha256user", "user"], foundUsers); - - MongoRunner.stopMongod(mongod); - - // Ensure mechanisms can be enabled and disabled. - mongod = MongoRunner.runMongod({ - auth: "", - setParameter: "authenticationMechanisms=SCRAM-SHA-1", - restart: mongod, - noCleanData: true - }); - assert(mongod.getDB("test").auth("sha1user", "pass")); - assert(!mongod.getDB("test").auth("sha256user", "pass")); - MongoRunner.stopMongod(mongod); - mongod = MongoRunner.runMongod({ - auth: "", - setParameter: "authenticationMechanisms=SCRAM-SHA-256", - restart: mongod, - noCleanData: true - }); - assert(!mongod.getDB("test").auth("sha1user", "pass")); - assert(mongod.getDB("test").auth("sha256user", "pass")); - MongoRunner.stopMongod(mongod); - +}); + +// Update original 1/256 user to just sha-1. +test.updateUser('user', {pwd: 'pass1', mechanisms: ['SCRAM-SHA-1']}); +checkUser('user', 'pass1', true, false); + +// Then flip to 256-only +test.updateUser('user', {pwd: 'pass256', mechanisms: ['SCRAM-SHA-256']}); +checkUser('user', 'pass256', false, true); + +// And back to (default) all. +test.updateUser('user', {pwd: 'passAll'}); +checkUser('user', 'passAll', true, true); + +// Trim out mechanisms without changing password. +test.updateUser('user', {mechanisms: ['SCRAM-SHA-256']}); +checkUser('user', 'passAll', false, true); + +// Fail when mechanisms is not a subset of the current user. +assert.throws(function() { + test.updateUser('user', {mechanisms: ['SCRAM-SHA-1']}); +}); + +// Fail when passing an empty mechanisms field. +assert.throws(function() { + test.updateUser('user', {pwd: 'passEmpty', mechanisms: []}); +}); + +// Succeed if we're using SHA-1 only. +test.createUser( + {user: "\u2168", pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); +checkUser("\u2168", 'pass', true, false); + +// Demonstrate that usersInfo returns all users with mechanisms lists +const allUsersInfo = assert.commandWorked(test.runCommand({usersInfo: 1})); +allUsersInfo.users.forEach(function(userObj) { + assert(Array.isArray(userObj.mechanisms)); +}); + +// Demonstrate that usersInfo can return all users with credentials +const allUsersInfoWithCredentials = + assert.commandWorked(test.runCommand({usersInfo: 1, showCredentials: true})); +allUsersInfoWithCredentials.users.forEach(function(userObj) { + assert(userObj.credentials !== undefined); + assert(!Array.isArray(userObj.credentials)); + assert(userObj.mechanisms !== undefined); + assert(Array.isArray(userObj.mechanisms)); +}); + +// Demonstrate that usersInfo can find SCRAM-SHA-1 users +const allSCRAMSHA1UsersInfo = + assert.commandWorked(test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-1"}})); +let foundUsers = []; +allSCRAMSHA1UsersInfo.users.forEach(function(userObj) { + foundUsers.push(userObj.user); +}); +assert.eq(["sha1user", "sha1user2", "\u2168"], foundUsers); + +// Demonstrate that usersInfo can find SCRAM-SHA-256 users +const allSCRAMSHA256UsersInfo = + assert.commandWorked(test.runCommand({usersInfo: 1, filter: {mechanisms: "SCRAM-SHA-256"}})); +foundUsers = []; +allSCRAMSHA256UsersInfo.users.forEach(function(userObj) { + foundUsers.push(userObj.user); +}); +assert.eq(["sha256user", "user"], foundUsers); + +MongoRunner.stopMongod(mongod); + +// Ensure mechanisms can be enabled and disabled. +mongod = MongoRunner.runMongod({ + auth: "", + setParameter: "authenticationMechanisms=SCRAM-SHA-1", + restart: mongod, + noCleanData: true +}); +assert(mongod.getDB("test").auth("sha1user", "pass")); +assert(!mongod.getDB("test").auth("sha256user", "pass")); +MongoRunner.stopMongod(mongod); +mongod = MongoRunner.runMongod({ + auth: "", + setParameter: "authenticationMechanisms=SCRAM-SHA-256", + restart: mongod, + noCleanData: true +}); +assert(!mongod.getDB("test").auth("sha1user", "pass")); +assert(mongod.getDB("test").auth("sha256user", "pass")); +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/user_management_commands_sharded_wc_1.js b/jstests/auth/user_management_commands_sharded_wc_1.js index f5dd2222636..675efba731a 100644 --- a/jstests/auth/user_management_commands_sharded_wc_1.js +++ b/jstests/auth/user_management_commands_sharded_wc_1.js @@ -3,13 +3,13 @@ */ (function() { - 'use strict'; +'use strict'; - load('jstests/auth/user_management_commands_lib.js'); +load('jstests/auth/user_management_commands_lib.js'); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest( - {shards: 2, config: 3, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); - runAllUserManagementCommandsTests(st.s, {w: 1}); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest( + {shards: 2, config: 3, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); +runAllUserManagementCommandsTests(st.s, {w: 1}); +st.stop(); })(); diff --git a/jstests/auth/user_management_commands_sharded_wc_majority.js b/jstests/auth/user_management_commands_sharded_wc_majority.js index e06f4b578c0..d9e0a75d543 100644 --- a/jstests/auth/user_management_commands_sharded_wc_majority.js +++ b/jstests/auth/user_management_commands_sharded_wc_majority.js @@ -1,13 +1,13 @@ // @tags: [requires_sharding] (function() { - 'use strict'; +'use strict'; - load('jstests/auth/user_management_commands_lib.js'); +load('jstests/auth/user_management_commands_lib.js'); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - var st = new ShardingTest( - {shards: 2, config: 3, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); - runAllUserManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); - st.stop(); +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +var st = new ShardingTest( + {shards: 2, config: 3, keyFile: 'jstests/libs/key1', other: {shardAsReplicaSet: false}}); +runAllUserManagementCommandsTests(st.s, {w: 'majority', wtimeout: 60 * 1000}); +st.stop(); })(); diff --git a/jstests/auth/user_management_commands_standalone.js b/jstests/auth/user_management_commands_standalone.js index 192f5968aa2..4f55c3dda81 100644 --- a/jstests/auth/user_management_commands_standalone.js +++ b/jstests/auth/user_management_commands_standalone.js @@ -1,9 +1,9 @@ (function() { - 'use strict'; +'use strict'; - load('jstests/auth/user_management_commands_lib.js'); +load('jstests/auth/user_management_commands_lib.js'); - var conn = MongoRunner.runMongod({auth: '', useHostname: false}); - runAllUserManagementCommandsTests(conn); - MongoRunner.stopMongod(conn); +var conn = MongoRunner.runMongod({auth: '', useHostname: false}); +runAllUserManagementCommandsTests(conn); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/user_special_chars.js b/jstests/auth/user_special_chars.js index fc968bc30b7..85ef75b48af 100644 --- a/jstests/auth/user_special_chars.js +++ b/jstests/auth/user_special_chars.js @@ -2,66 +2,65 @@ // Test creating and authenticating users with special characters. (function() { - var conn = MongoRunner.runMongod({auth: ''}); +var conn = MongoRunner.runMongod({auth: ''}); - var adminDB = conn.getDB('admin'); - adminDB.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +var adminDB = conn.getDB('admin'); +adminDB.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); - var testUserSpecialCharacters = function() { +var testUserSpecialCharacters = function() { + // Create a user with special characters, make sure it can auth. + assert(adminDB.auth('admin', 'pass')); + adminDB.createUser( + {user: '~`!@#$%^&*()-_+={}[]||;:",.//><', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(adminDB.logout()); - // Create a user with special characters, make sure it can auth. - assert(adminDB.auth('admin', 'pass')); - adminDB.createUser( - {user: '~`!@#$%^&*()-_+={}[]||;:",.//><', pwd: 'pass', roles: jsTest.adminUserRoles}); - assert(adminDB.logout()); + assert(adminDB.auth({user: '~`!@#$%^&*()-_+={}[]||;:",.//><', pwd: 'pass'})); + assert(adminDB.logout()); +}; +testUserSpecialCharacters(); - assert(adminDB.auth({user: '~`!@#$%^&*()-_+={}[]||;:",.//><', pwd: 'pass'})); - assert(adminDB.logout()); - }; - testUserSpecialCharacters(); +var testUserAndDatabaseAtSymbolConflation = function() { + // Create a pair of users and databases such that their string representations are + // identical. + assert(adminDB.auth('admin', 'pass')); - var testUserAndDatabaseAtSymbolConflation = function() { - // Create a pair of users and databases such that their string representations are - // identical. - assert(adminDB.auth('admin', 'pass')); + var bcDB = conn.getDB('b@c'); + bcDB.createUser({user: 'a', pwd: 'pass2', roles: [{role: 'readWrite', db: 'b@c'}]}); - var bcDB = conn.getDB('b@c'); - bcDB.createUser({user: 'a', pwd: 'pass2', roles: [{role: 'readWrite', db: 'b@c'}]}); + var cDB = conn.getDB('c'); + cDB.createUser({user: 'a@b', pwd: 'pass1', roles: [{role: 'readWrite', db: 'c'}]}); - var cDB = conn.getDB('c'); - cDB.createUser({user: 'a@b', pwd: 'pass1', roles: [{role: 'readWrite', db: 'c'}]}); + assert(adminDB.logout()); - assert(adminDB.logout()); + // Ensure they cannot authenticate to the wrong database. + assert(!bcDB.auth('a@b', 'pass1')); + assert(!bcDB.auth('a@b', 'pass2')); + assert(!cDB.auth('a', 'pass1')); + assert(!cDB.auth('a', 'pass2')); - // Ensure they cannot authenticate to the wrong database. - assert(!bcDB.auth('a@b', 'pass1')); - assert(!bcDB.auth('a@b', 'pass2')); - assert(!cDB.auth('a', 'pass1')); - assert(!cDB.auth('a', 'pass2')); + // Ensure that they can both successfully authenticate to their correct database. + assert(cDB.auth('a@b', 'pass1')); + assert.writeOK(cDB.col.insert({data: 1})); + assert.writeError(bcDB.col.insert({data: 2})); + assert(cDB.logout()); - // Ensure that they can both successfully authenticate to their correct database. - assert(cDB.auth('a@b', 'pass1')); - assert.writeOK(cDB.col.insert({data: 1})); - assert.writeError(bcDB.col.insert({data: 2})); - assert(cDB.logout()); + assert(bcDB.auth('a', 'pass2')); + assert.writeOK(bcDB.col.insert({data: 3})); + assert.writeError(cDB.col.insert({data: 4})); + assert(bcDB.logout()); - assert(bcDB.auth('a', 'pass2')); - assert.writeOK(bcDB.col.insert({data: 3})); - assert.writeError(cDB.col.insert({data: 4})); - assert(bcDB.logout()); + // Ensure that the user cache permits both users to log in at the same time + assert(cDB.auth('a@b', 'pass1')); + assert(bcDB.auth('a', 'pass2')); + assert(cDB.logout()); + assert(bcDB.logout()); - // Ensure that the user cache permits both users to log in at the same time - assert(cDB.auth('a@b', 'pass1')); - assert(bcDB.auth('a', 'pass2')); - assert(cDB.logout()); - assert(bcDB.logout()); + assert(bcDB.auth('a', 'pass2')); + assert(cDB.auth('a@b', 'pass1')); + assert(cDB.logout()); + assert(bcDB.logout()); +}; +testUserAndDatabaseAtSymbolConflation(); - assert(bcDB.auth('a', 'pass2')); - assert(cDB.auth('a@b', 'pass1')); - assert(cDB.logout()); - assert(bcDB.logout()); - }; - testUserAndDatabaseAtSymbolConflation(); - - MongoRunner.stopMongod(conn); +MongoRunner.stopMongod(conn); })(); diff --git a/jstests/auth/usersInfo.js b/jstests/auth/usersInfo.js index fdd4a1b0a5f..81b9b4ee870 100644 --- a/jstests/auth/usersInfo.js +++ b/jstests/auth/usersInfo.js @@ -1,47 +1,46 @@ // Test behavior and edge cases in usersInfo (function() { - 'use strict'; - - function runTest(conn) { - let db = conn.getDB("test"); - let emptyDB = conn.getDB("test2"); - let otherDB = conn.getDB("other"); - - const userCount = 200; - for (let i = 0; i < userCount; ++i) { - assert.commandWorked(db.runCommand({createUser: "user" + i, pwd: "pwd", roles: []})); - } - assert.commandWorked(otherDB.runCommand({createUser: "otherUser", pwd: "pwd", roles: []})); - - // Check info for all users on the "test" database. - const allTestInfo = assert.commandWorked(db.runCommand({usersInfo: 1})); - assert.eq(userCount, allTestInfo.users.length); - - // Check we can find a particular user on the "test" database. - assert.eq(1, assert.commandWorked(db.runCommand({usersInfo: "user12"})).users.length); - assert.eq(1, - assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test"}})) - .users.length); - assert.eq(0, - assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test2"}})) - .users.length); - assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: "user12"})).users.length); - - // No users are found on a database without users. - assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: 1})).users.length); - - // Check that we can find records for all users on all databases. - const allInfo = assert.commandWorked(db.runCommand({usersInfo: {forAllDBs: true}})); - assert.eq(userCount + 1, allInfo.users.length); - } +'use strict'; - const m = MongoRunner.runMongod(); - runTest(m); - MongoRunner.stopMongod(m); +function runTest(conn) { + let db = conn.getDB("test"); + let emptyDB = conn.getDB("test2"); + let otherDB = conn.getDB("other"); - // TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. - const st = - new ShardingTest({shards: 1, mongos: 1, config: 1, other: {shardAsReplicaSet: false}}); - runTest(st.s0); - st.stop(); + const userCount = 200; + for (let i = 0; i < userCount; ++i) { + assert.commandWorked(db.runCommand({createUser: "user" + i, pwd: "pwd", roles: []})); + } + assert.commandWorked(otherDB.runCommand({createUser: "otherUser", pwd: "pwd", roles: []})); + + // Check info for all users on the "test" database. + const allTestInfo = assert.commandWorked(db.runCommand({usersInfo: 1})); + assert.eq(userCount, allTestInfo.users.length); + + // Check we can find a particular user on the "test" database. + assert.eq(1, assert.commandWorked(db.runCommand({usersInfo: "user12"})).users.length); + assert.eq(1, + assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test"}})) + .users.length); + assert.eq(0, + assert.commandWorked(db.runCommand({usersInfo: {user: "user12", db: "test2"}})) + .users.length); + assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: "user12"})).users.length); + + // No users are found on a database without users. + assert.eq(0, assert.commandWorked(emptyDB.runCommand({usersInfo: 1})).users.length); + + // Check that we can find records for all users on all databases. + const allInfo = assert.commandWorked(db.runCommand({usersInfo: {forAllDBs: true}})); + assert.eq(userCount + 1, allInfo.users.length); +} + +const m = MongoRunner.runMongod(); +runTest(m); +MongoRunner.stopMongod(m); + +// TODO: Remove 'shardAsReplicaSet: false' when SERVER-32672 is fixed. +const st = new ShardingTest({shards: 1, mongos: 1, config: 1, other: {shardAsReplicaSet: false}}); +runTest(st.s0); +st.stop(); }()); diff --git a/jstests/auth/validate_auth_schema_on_startup.js b/jstests/auth/validate_auth_schema_on_startup.js index 764308a3644..e4c6c50fdcc 100644 --- a/jstests/auth/validate_auth_schema_on_startup.js +++ b/jstests/auth/validate_auth_schema_on_startup.js @@ -6,47 +6,46 @@ */ (function() { - const dbpath = MongoRunner.dataPath + "validateAuthSchemaOnStartup/"; - resetDbpath(dbpath); - const dbName = "validateAuthSchemaOnStartup"; - const authSchemaColl = "system.version"; +const dbpath = MongoRunner.dataPath + "validateAuthSchemaOnStartup/"; +resetDbpath(dbpath); +const dbName = "validateAuthSchemaOnStartup"; +const authSchemaColl = "system.version"; - let mongod = MongoRunner.runMongod({dbpath: dbpath, auth: ""}); - let adminDB = mongod.getDB('admin'); +let mongod = MongoRunner.runMongod({dbpath: dbpath, auth: ""}); +let adminDB = mongod.getDB('admin'); - // Create a user. - adminDB.createUser( - {user: "root", pwd: "root", roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]}); - assert(adminDB.auth("root", "root")); +// Create a user. +adminDB.createUser( + {user: "root", pwd: "root", roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]}); +assert(adminDB.auth("root", "root")); - MongoRunner.stopMongod(mongod); +MongoRunner.stopMongod(mongod); - // Start without auth to corrupt the authSchema document. - mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true}); - adminDB = mongod.getDB('admin'); +// Start without auth to corrupt the authSchema document. +mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true}); +adminDB = mongod.getDB('admin'); - let currentVersion = adminDB[authSchemaColl].findOne({_id: 'authSchema'}).currentVersion; +let currentVersion = adminDB[authSchemaColl].findOne({_id: 'authSchema'}).currentVersion; - // Invalidate the authSchema document. - assert.commandWorked( - adminDB[authSchemaColl].update({_id: 'authSchema'}, {currentVersion: 'asdf'})); - MongoRunner.stopMongod(mongod); +// Invalidate the authSchema document. +assert.commandWorked(adminDB[authSchemaColl].update({_id: 'authSchema'}, {currentVersion: 'asdf'})); +MongoRunner.stopMongod(mongod); - // Confirm start up fails, even without --auth. - assert.eq(null, MongoRunner.runMongod({dbpath: dbpath, noCleanData: true})); +// Confirm start up fails, even without --auth. +assert.eq(null, MongoRunner.runMongod({dbpath: dbpath, noCleanData: true})); - // Confirm startup works with the flag to disable validation so the document can be repaired. - mongod = MongoRunner.runMongod( - {dbpath: dbpath, noCleanData: true, setParameter: "startupAuthSchemaValidation=false"}); - adminDB = mongod.getDB('admin'); - assert.commandWorked( - adminDB[authSchemaColl].update({_id: 'authSchema'}, {currentVersion: currentVersion})); - MongoRunner.stopMongod(mongod); +// Confirm startup works with the flag to disable validation so the document can be repaired. +mongod = MongoRunner.runMongod( + {dbpath: dbpath, noCleanData: true, setParameter: "startupAuthSchemaValidation=false"}); +adminDB = mongod.getDB('admin'); +assert.commandWorked( + adminDB[authSchemaColl].update({_id: 'authSchema'}, {currentVersion: currentVersion})); +MongoRunner.stopMongod(mongod); - // Confirm everything is normal again. - mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true, auth: ""}); - adminDB = mongod.getDB('admin'); - assert(adminDB.auth("root", "root")); +// Confirm everything is normal again. +mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true, auth: ""}); +adminDB = mongod.getDB('admin'); +assert(adminDB.auth("root", "root")); - MongoRunner.stopMongod(mongod); +MongoRunner.stopMongod(mongod); })(); diff --git a/jstests/auth/views_authz.js b/jstests/auth/views_authz.js index 080a4b2bfcd..6223312249c 100644 --- a/jstests/auth/views_authz.js +++ b/jstests/auth/views_authz.js @@ -4,155 +4,142 @@ * @tags: [requires_sharding] */ (function() { - "use strict"; +"use strict"; - // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. - TestData.disableImplicitSessions = true; +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; - function runTest(conn) { - // Create the admin user. - let adminDB = conn.getDB("admin"); - assert.commandWorked( - adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]})); - assert.eq(1, adminDB.auth("admin", "admin")); +function runTest(conn) { + // Create the admin user. + let adminDB = conn.getDB("admin"); + assert.commandWorked(adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]})); + assert.eq(1, adminDB.auth("admin", "admin")); - const viewsDBName = "views_authz"; - let viewsDB = adminDB.getSiblingDB(viewsDBName); - viewsDB.dropAllUsers(); - viewsDB.logout(); + const viewsDBName = "views_authz"; + let viewsDB = adminDB.getSiblingDB(viewsDBName); + viewsDB.dropAllUsers(); + viewsDB.logout(); - // Create a user who can read, create and modify a view 'view' and a read a namespace - // 'permitted' but does not have access to 'forbidden'. - assert.commandWorked(viewsDB.runCommand({ - createRole: "readWriteView", - privileges: [ - { - resource: {db: viewsDBName, collection: "view"}, - actions: ["find", "createCollection", "collMod"] - }, - {resource: {db: viewsDBName, collection: "view2"}, actions: ["find"]}, - {resource: {db: viewsDBName, collection: "permitted"}, actions: ["find"]} - ], - roles: [] - })); - assert.commandWorked( - viewsDB.runCommand({createUser: "viewUser", pwd: "pwd", roles: ["readWriteView"]})); + // Create a user who can read, create and modify a view 'view' and a read a namespace + // 'permitted' but does not have access to 'forbidden'. + assert.commandWorked(viewsDB.runCommand({ + createRole: "readWriteView", + privileges: [ + { + resource: {db: viewsDBName, collection: "view"}, + actions: ["find", "createCollection", "collMod"] + }, + {resource: {db: viewsDBName, collection: "view2"}, actions: ["find"]}, + {resource: {db: viewsDBName, collection: "permitted"}, actions: ["find"]} + ], + roles: [] + })); + assert.commandWorked( + viewsDB.runCommand({createUser: "viewUser", pwd: "pwd", roles: ["readWriteView"]})); - adminDB.logout(); - assert.eq(1, viewsDB.auth("viewUser", "pwd")); + adminDB.logout(); + assert.eq(1, viewsDB.auth("viewUser", "pwd")); - const lookupStage = { - $lookup: {from: "forbidden", localField: "x", foreignField: "x", as: "y"} - }; - const graphLookupStage = { - $graphLookup: { - from: "forbidden", - startWith: [], - connectFromField: "x", - connectToField: "x", - as: "y" - } - }; + const lookupStage = {$lookup: {from: "forbidden", localField: "x", foreignField: "x", as: "y"}}; + const graphLookupStage = { + $graphLookup: + {from: "forbidden", startWith: [], connectFromField: "x", connectToField: "x", as: "y"} + }; - // You cannot create a view if you have both the 'createCollection' and 'find' actions on - // that view but not the 'find' action on all of the dependent namespaces. - assert.commandFailedWithCode(viewsDB.createView("view", "forbidden", []), - ErrorCodes.Unauthorized, - "created a readable view on an unreadable collection"); - assert.commandFailedWithCode( - viewsDB.createView("view", "permitted", [lookupStage]), - ErrorCodes.Unauthorized, - "created a readable view on an unreadable collection via $lookup"); - assert.commandFailedWithCode( - viewsDB.createView("view", "permitted", [graphLookupStage]), - ErrorCodes.Unauthorized, - "created a readable view on an unreadable collection via $graphLookup"); - assert.commandFailedWithCode( - viewsDB.createView("view", "permitted", [{$facet: {a: [lookupStage]}}]), - ErrorCodes.Unauthorized, - "created a readable view on an unreadable collection via $lookup in a $facet"); - assert.commandFailedWithCode( - viewsDB.createView("view", "permitted", [{$facet: {b: [graphLookupStage]}}]), - ErrorCodes.Unauthorized, - "created a readable view on an unreadable collection via $graphLookup in a $facet"); + // You cannot create a view if you have both the 'createCollection' and 'find' actions on + // that view but not the 'find' action on all of the dependent namespaces. + assert.commandFailedWithCode(viewsDB.createView("view", "forbidden", []), + ErrorCodes.Unauthorized, + "created a readable view on an unreadable collection"); + assert.commandFailedWithCode(viewsDB.createView("view", "permitted", [lookupStage]), + ErrorCodes.Unauthorized, + "created a readable view on an unreadable collection via $lookup"); + assert.commandFailedWithCode( + viewsDB.createView("view", "permitted", [graphLookupStage]), + ErrorCodes.Unauthorized, + "created a readable view on an unreadable collection via $graphLookup"); + assert.commandFailedWithCode( + viewsDB.createView("view", "permitted", [{$facet: {a: [lookupStage]}}]), + ErrorCodes.Unauthorized, + "created a readable view on an unreadable collection via $lookup in a $facet"); + assert.commandFailedWithCode( + viewsDB.createView("view", "permitted", [{$facet: {b: [graphLookupStage]}}]), + ErrorCodes.Unauthorized, + "created a readable view on an unreadable collection via $graphLookup in a $facet"); - assert.commandWorked(viewsDB.createView("view", "permitted", [{$match: {x: 1}}])); + assert.commandWorked(viewsDB.createView("view", "permitted", [{$match: {x: 1}}])); - // You cannot modify a view if you have both the 'collMod' and 'find' actions on that view - // but not the 'find' action on all of the dependent namespaces. - assert.commandFailedWithCode( - viewsDB.runCommand({collMod: "view", viewOn: "forbidden", pipeline: [{$match: {}}]}), - ErrorCodes.Unauthorized, - "modified a view to read an unreadable collection"); - assert.commandFailedWithCode( - viewsDB.runCommand({collMod: "view", viewOn: "permitted", pipeline: [lookupStage]}), - ErrorCodes.Unauthorized, - "modified a view to read an unreadable collection via $lookup"); - assert.commandFailedWithCode( - viewsDB.runCommand( - {collMod: "view", viewOn: "permitted", pipeline: [graphLookupStage]}), - ErrorCodes.Unauthorized, - "modified a view to read an unreadable collection via $graphLookup"); - assert.commandFailedWithCode( - viewsDB.runCommand( - {collMod: "view", viewOn: "permitted", pipeline: [{$facet: {a: [lookupStage]}}]}), - ErrorCodes.Unauthorized, - "modified a view to read an unreadable collection via $lookup in a $facet"); - assert.commandFailedWithCode( - viewsDB.runCommand({ - collMod: "view", - viewOn: "permitted", - pipeline: [{$facet: {b: [graphLookupStage]}}] - }), - ErrorCodes.Unauthorized, - "modified a view to read an unreadable collection via $graphLookup in a $facet"); + // You cannot modify a view if you have both the 'collMod' and 'find' actions on that view + // but not the 'find' action on all of the dependent namespaces. + assert.commandFailedWithCode( + viewsDB.runCommand({collMod: "view", viewOn: "forbidden", pipeline: [{$match: {}}]}), + ErrorCodes.Unauthorized, + "modified a view to read an unreadable collection"); + assert.commandFailedWithCode( + viewsDB.runCommand({collMod: "view", viewOn: "permitted", pipeline: [lookupStage]}), + ErrorCodes.Unauthorized, + "modified a view to read an unreadable collection via $lookup"); + assert.commandFailedWithCode( + viewsDB.runCommand({collMod: "view", viewOn: "permitted", pipeline: [graphLookupStage]}), + ErrorCodes.Unauthorized, + "modified a view to read an unreadable collection via $graphLookup"); + assert.commandFailedWithCode( + viewsDB.runCommand( + {collMod: "view", viewOn: "permitted", pipeline: [{$facet: {a: [lookupStage]}}]}), + ErrorCodes.Unauthorized, + "modified a view to read an unreadable collection via $lookup in a $facet"); + assert.commandFailedWithCode( + viewsDB.runCommand( + {collMod: "view", viewOn: "permitted", pipeline: [{$facet: {b: [graphLookupStage]}}]}), + ErrorCodes.Unauthorized, + "modified a view to read an unreadable collection via $graphLookup in a $facet"); - // When auth is enabled, users must specify both "viewOn" and "pipeline" when running - // collMod on a view; specifying only one or the other is not allowed. Without both the - // "viewOn" and "pipeline" specified, authorization checks cannot determine if the users - // have the necessary privileges. - assert.commandFailedWithCode(viewsDB.runCommand({collMod: "view", pipeline: []}), - ErrorCodes.InvalidOptions, - "modified a view without having to specify 'viewOn'"); - assert.commandFailedWithCode(viewsDB.runCommand({collMod: "view", viewOn: "other"}), - ErrorCodes.InvalidOptions, - "modified a view without having to specify 'pipeline'"); + // When auth is enabled, users must specify both "viewOn" and "pipeline" when running + // collMod on a view; specifying only one or the other is not allowed. Without both the + // "viewOn" and "pipeline" specified, authorization checks cannot determine if the users + // have the necessary privileges. + assert.commandFailedWithCode(viewsDB.runCommand({collMod: "view", pipeline: []}), + ErrorCodes.InvalidOptions, + "modified a view without having to specify 'viewOn'"); + assert.commandFailedWithCode(viewsDB.runCommand({collMod: "view", viewOn: "other"}), + ErrorCodes.InvalidOptions, + "modified a view without having to specify 'pipeline'"); - // Create a view on a forbidden collection and populate it. - assert.eq(1, adminDB.auth("admin", "admin")); - assert.commandWorked(viewsDB.createView("view2", "forbidden", [])); - for (let i = 0; i < 10; i++) { - assert.writeOK(viewsDB.forbidden.insert({x: 1})); - } - adminDB.logout(); - - // Performing a find on a readable view returns a cursor that allows us to perform a getMore - // even if the underlying collection is unreadable. - assert.commandFailedWithCode(viewsDB.runCommand({find: "forbidden"}), - ErrorCodes.Unauthorized, - "successfully performed a find on an unreadable namespace"); - let res = viewsDB.runCommand({find: "view2", batchSize: 1}); - assert.commandWorked(res, "could not perform a find on a readable view"); - assert.eq(res.cursor.ns, - "views_authz.view2", - "performing find on a view does not return a cursor on the view namespace"); - assert.commandWorked(viewsDB.runCommand({getMore: res.cursor.id, collection: "view2"}), - "could not perform getMore on a readable view"); + // Create a view on a forbidden collection and populate it. + assert.eq(1, adminDB.auth("admin", "admin")); + assert.commandWorked(viewsDB.createView("view2", "forbidden", [])); + for (let i = 0; i < 10; i++) { + assert.writeOK(viewsDB.forbidden.insert({x: 1})); } + adminDB.logout(); + + // Performing a find on a readable view returns a cursor that allows us to perform a getMore + // even if the underlying collection is unreadable. + assert.commandFailedWithCode(viewsDB.runCommand({find: "forbidden"}), + ErrorCodes.Unauthorized, + "successfully performed a find on an unreadable namespace"); + let res = viewsDB.runCommand({find: "view2", batchSize: 1}); + assert.commandWorked(res, "could not perform a find on a readable view"); + assert.eq(res.cursor.ns, + "views_authz.view2", + "performing find on a view does not return a cursor on the view namespace"); + assert.commandWorked(viewsDB.runCommand({getMore: res.cursor.id, collection: "view2"}), + "could not perform getMore on a readable view"); +} - // Run the test on a standalone. - let mongod = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"}); - runTest(mongod); - MongoRunner.stopMongod(mongod); +// Run the test on a standalone. +let mongod = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"}); +runTest(mongod); +MongoRunner.stopMongod(mongod); - // 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(); +// 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(); }()); |