diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2022-02-04 19:05:54 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-02-24 02:51:46 +0000 |
commit | e4032fe5c39f1974c76de4cefdc07d98ab25aeef (patch) | |
tree | 3bba629166e40d1455cfc1cd65d299311670c535 | |
parent | e9f462ba1ec6c1c105fab71239b9a958ae106484 (diff) | |
download | mongo-e4032fe5c39f1974c76de4cefdc07d98ab25aeef.tar.gz |
SERVER-57369 Disable concurrent authentication
45 files changed, 1051 insertions, 1164 deletions
diff --git a/jstests/auth/auth-counters.js b/jstests/auth/auth-counters.js index b74fa531725..b1c6b54d4af 100644 --- a/jstests/auth/auth-counters.js +++ b/jstests/auth/auth-counters.js @@ -25,8 +25,14 @@ test.createUser( // Count the number of authentications performed during setup const expected = assert.commandWorked(admin.runCommand({serverStatus: 1})).security.authentication.mechanisms; +admin.logout(); function assertStats() { + // Need to be authenticated to run serverStatus. + assert(admin.auth('admin', 'pwd')); + ++expected['SCRAM-SHA-256'].authenticate.successful; + ++expected['SCRAM-SHA-256'].authenticate.received; + const mechStats = assert.commandWorked(admin.runCommand({serverStatus: 1})) .security.authentication.mechanisms; Object.keys(expected).forEach(function(mech) { @@ -45,13 +51,13 @@ function assertStats() { throw e; } }); + + admin.logout(); } function assertSuccess(creds, mech, db = test) { assert.eq(db.auth(creds), true); - if (db !== admin) { - db.logout(); - } + db.logout(); ++expected[mech].authenticate.received; ++expected[mech].authenticate.successful; assertStats(); diff --git a/jstests/auth/auth_mechanism_discovery.js b/jstests/auth/auth_mechanism_discovery.js index d17d1ddb03b..28d0a531d18 100644 --- a/jstests/auth/auth_mechanism_discovery.js +++ b/jstests/auth/auth_mechanism_discovery.js @@ -8,18 +8,19 @@ function runTest(conn) { const test = conn.getDB("test"); 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: []}; + const 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(admin.auth('admin', 'pass')); assert.commandWorked(test.runCommand(createUser)); + admin.logout(); assert.eq(test._getDefaultAuthenticationMechanism(username, test.getName()), mechanism); assert(test.auth(username, 'pwd')); test.logout(); diff --git a/jstests/auth/authentication_restrictions.js b/jstests/auth/authentication_restrictions.js index 9de899ef592..81d04565299 100644 --- a/jstests/auth/authentication_restrictions.js +++ b/jstests/auth/authentication_restrictions.js @@ -14,96 +14,105 @@ function testConnection( load("jstests/libs/host_ipaddr.js"); // Create a session which observes an eventually consistent view of user data - var eventualDb = eventuallyConsistentConn.getDB("admin"); + const 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"); + const adminSession = new Mongo("localhost:" + conn.port); + const admin = adminSession.getDB("admin"); assert.commandWorked(admin.runCommand( {createUser: "admin", pwd: "admin", roles: [{role: "root", db: "admin"}]})); assert(admin.auth("admin", "admin")); + admin.logout(); // Create a strongly consistent session for consuming user data - var db = conn.getDB("admin"); + const 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"); + const externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); + const externalDb = externalMongo.getDB("admin"); - assert.commandWorked(admin.runCommand({ + // Create a connection which remains authenticated as 'admin' + // so that we can create/mutate users/roles while we do + // multiple authentications. + const adminMongo = new Mongo(conn.host); + const adminDB = adminMongo.getDB('admin'); + assert(adminDB.auth('admin', 'admin')); + + assert.commandWorked(adminDB.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( + assert.commandWorked(adminDB.runCommand({createUser: "user3", pwd: "user", roles: []})); + assert.commandWorked(adminDB.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( + assert.commandWorked(adminDB.runCommand( {createUser: "user4", pwd: "user", roles: [], authenticationRestrictions: []})); - assert(!Object.keys(admin.system.users.findOne({user: "user4"})) + assert(!Object.keys(adminDB.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"})) + assert.commandWorked(adminDB.runCommand({createUser: "user5", pwd: "user", roles: []})); + assert.commandWorked(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: []})); + assert(!Object.keys(adminDB.system.users.findOne({user: "user5"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.runCommand( {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) + assert(Object.keys(adminDB.system.users.findOne({user: "user5"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({updateUser: "user5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.users.findOne({user: "user5"})) + assert.commandWorked(adminDB.runCommand({updateUser: "user5", authenticationRestrictions: []})); + assert(!Object.keys(adminDB.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( + assert.commandWorked(adminDB.runCommand( {updateUser: "user5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) + assert(Object.keys(adminDB.system.users.findOne({user: "user5"})) .includes("authenticationRestrictions")); - assert.commandFailed(admin.runCommand({updateUser: "user5", authenticationRestrictions: null})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) + assert.commandFailed( + adminDB.runCommand({updateUser: "user5", authenticationRestrictions: null})); + assert(Object.keys(adminDB.system.users.findOne({user: "user5"})) .includes("authenticationRestrictions")); assert.commandFailed( - admin.runCommand({updateUser: "user5", authenticationRestrictions: undefined})); - assert(Object.keys(admin.system.users.findOne({user: "user5"})) + adminDB.runCommand({updateUser: "user5", authenticationRestrictions: undefined})); + assert(Object.keys(adminDB.system.users.findOne({user: "user5"})) .includes("authenticationRestrictions")); print( "When a client creates users, it may use clientSource and serverAddress authenticationRestrictions"); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createUser: "user6", pwd: "user", roles: [], authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] })); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createUser: "user7", pwd: "user", roles: [], authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] })); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createUser: "user8", pwd: "user", roles: [], authenticationRestrictions: [{clientSource: ["127.0.0.1"], serverAddress: ["127.0.0.1"]}] })); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createUser: "user9", pwd: "user", roles: [], authenticationRestrictions: [{clientSource: ["127.0.0.1"]}, {serverAddress: ["127.0.0.1"]}] })); - assert.commandFailed(admin.runCommand({ + assert.commandFailed(adminDB.runCommand({ createUser: "user10", pwd: "user", roles: [], @@ -115,14 +124,17 @@ function testConnection( 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")); + db.logout(); 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")); + db.logout(); 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")); + db.logout(); print("=== Remote access tests"); print( @@ -140,51 +152,54 @@ function testConnection( print("=== Invalidation tests"); print( "When a client removes all authenticationRestrictions from a user, authentication will succeed"); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.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.commandWorked( + adminDB.runCommand({updateUser: "user11", authenticationRestrictions: []})); assert(externalDb.auth("user11", "user")); + externalDb.logout(); print( "When a client sets authenticationRestrictions on a user, authorization privileges are revoked"); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.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})); + db.logout(); sleepUntilUserDataPropagated(); assert(eventualDb.auth("user12", "user")); assert.commandWorked(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.runCommand( {updateUser: "user12", authenticationRestrictions: [{clientSource: ["192.0.2.0"]}]})); - assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + assert(!db.auth('user12', 'user')); sleepUntilUserDataRefreshed(); assert.commandFailed(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); } print("Testing standalone"); -var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); +const conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); testConnection(conn, conn, function() {}, function() {}); MongoRunner.stopMongod(conn); -var keyfile = "jstests/libs/key1"; +const keyfile = "jstests/libs/key1"; print("Testing replicaset"); -var rst = new ReplSetTest( +const rst = new ReplSetTest( {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); -var nodes = rst.startSet(); +const nodes = rst.startSet(); rst.initiate(); rst.awaitSecondaryNodes(); -var awaitReplication = function() { +const awaitReplication = function() { authutil.asCluster(nodes, "jstests/libs/key1", function() { rst.awaitReplication(); }); @@ -194,7 +209,7 @@ testConnection(rst.getPrimary(), rst.getSecondary(), awaitReplication, awaitRepl rst.stopSet(); print("Testing sharded cluster"); -var st = new ShardingTest({ +const st = new ShardingTest({ mongos: 2, config: 3, shard: 1, diff --git a/jstests/auth/authentication_restrictions_role.js b/jstests/auth/authentication_restrictions_role.js index e663e7e3b33..627edb6e618 100644 --- a/jstests/auth/authentication_restrictions_role.js +++ b/jstests/auth/authentication_restrictions_role.js @@ -14,98 +14,105 @@ function testRestrictionCreationAndEnforcement( load("jstests/libs/host_ipaddr.js"); // Create a session which observes an eventually consistent view of user data - var eventualDb = eventuallyConsistentConn.getDB("admin"); + const 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"); + const adminSession = new Mongo("127.0.0.1:" + conn.port); + const 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"); + const 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"); + const externalMongo = new Mongo(get_ipaddr() + ":" + conn.port); + const externalDb = externalMongo.getDB("admin"); - assert.commandWorked(admin.runCommand({ + // Create a connection which remains authenticated as 'admin' + // so that we can create/mutate users/roles while we do + // multiple authentications. + const adminMongo = new Mongo(conn.host); + const adminDB = adminMongo.getDB('admin'); + assert(adminDB.auth('admin', 'admin')); + + assert.commandWorked(adminDB.runCommand({ createRole: "role2", roles: [], privileges: [], authenticationRestrictions: [{clientSource: ["127.0.0.1/32"]}] })); - assert(Object.keys(admin.system.roles.findOne({role: "role2"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role2"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({createRole: "role3", roles: [], privileges: []})); + assert.commandWorked(adminDB.runCommand({createRole: "role3", roles: [], privileges: []})); print("=== Role creation tests"); print("When a role is updated, it retains authenticationRestrictions"); - assert.commandWorked(admin.runCommand({updateRole: "role2", roles: ["root"]})); + assert.commandWorked(adminDB.runCommand({updateRole: "role2", roles: ["root"]})); const role2Info = assert.commandWorked( - admin.runCommand({rolesInfo: "role2", showAuthenticationRestrictions: true})); + adminDB.runCommand({rolesInfo: "role2", showAuthenticationRestrictions: true})); printjson(role2Info); assert.eq(JSON.stringify([[{clientSource: ["127.0.0.1/32"]}]]), JSON.stringify(role2Info.roles[0].authenticationRestrictions)); print( "When a client creates roles with empty authenticationRestrictions, the operation succeeds, though it has no effect"); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.runCommand( {createRole: "role4", roles: [], privileges: [], authenticationRestrictions: []})); - assert(!Object.keys(admin.system.roles.findOne({role: "role4"})) + assert(!Object.keys(adminDB.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"})) + assert.commandWorked(adminDB.runCommand({createRole: "role5", roles: [], privileges: []})); + assert.commandWorked(adminDB.runCommand({updateRole: "role5", authenticationRestrictions: []})); + assert(!Object.keys(adminDB.system.roles.findOne({role: "role5"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.runCommand( {updateRole: "role5", authenticationRestrictions: [{clientSource: ["127.0.0.1"]}]})); - assert(Object.keys(admin.system.roles.findOne({role: "role5"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role5"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({updateRole: "role5", authenticationRestrictions: []})); - assert(!Object.keys(admin.system.roles.findOne({role: "role5"})) + assert.commandWorked(adminDB.runCommand({updateRole: "role5", authenticationRestrictions: []})); + assert(!Object.keys(adminDB.system.roles.findOne({role: "role5"})) .includes("authenticationRestrictions")); print( "When a client creates roles, it may use clientSource and serverAddress authenticationRestrictions"); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createRole: "role6", roles: [], privileges: [], authenticationRestrictions: [{clientSource: ["127.0.0.1"]}] })); - assert(Object.keys(admin.system.roles.findOne({role: "role6"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role6"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.runCommand({ createRole: "role7", roles: [], privileges: [], authenticationRestrictions: [{serverAddress: ["127.0.0.1"]}] })); - assert(Object.keys(admin.system.roles.findOne({role: "role7"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role7"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.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"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role8"})) .includes("authenticationRestrictions")); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.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"})) + assert(Object.keys(adminDB.system.roles.findOne({role: "role9"})) .includes("authenticationRestrictions")); - assert.commandFailed(admin.runCommand({ + assert.commandFailed(adminDB.runCommand({ createRole: "role10", roles: [], privileges: [], @@ -115,18 +122,21 @@ function testRestrictionCreationAndEnforcement( 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.commandWorked(adminDB.runCommand({createUser: "user6", pwd: "user", roles: ["role6"]})); assert(db.auth("user6", "user")); + db.logout(); 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.commandWorked(adminDB.runCommand({createUser: "user7", pwd: "user", roles: ["role7"]})); assert(db.auth("user7", "user")); + db.logout(); 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.commandWorked(adminDB.runCommand({createUser: "user8", pwd: "user", roles: ["role8"]})); assert(db.auth("user8", "user")); + db.logout(); print("=== Remote access tests"); print( @@ -144,36 +154,45 @@ function testRestrictionCreationAndEnforcement( print("=== Invalidation tests"); print( "When a client removes all authenticationRestrictions from a role, authentication will succeed"); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.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.commandWorked( + adminDB.runCommand({createUser: "user11", pwd: "user", roles: ["role11"]})); assert(!externalDb.auth("user11", "user")); - assert.commandWorked(admin.runCommand({updateRole: "role11", authenticationRestrictions: []})); + assert.commandWorked( + adminDB.runCommand({updateRole: "role11", authenticationRestrictions: []})); assert(externalDb.auth("user11", "user")); + externalDb.logout(); print( "When a client sets authenticationRestrictions on a role, authorization privileges are revoked"); - assert.commandWorked(admin.runCommand({ + assert.commandWorked(adminDB.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.commandWorked( + adminDB.runCommand({createUser: "user12", pwd: "user", roles: ["role12"]})); assert(db.auth("user12", "user")); assert.commandWorked(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + db.logout(); + sleepUntilUserDataPropagated(); + assert(eventualDb.auth("user12", "user")); assert.commandWorked(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); - assert.commandWorked(admin.runCommand( + assert.commandWorked(adminDB.runCommand( {updateRole: "role12", authenticationRestrictions: [{clientSource: ["192.168.2.0"]}]})); assert.commandFailed(db.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + eventualDb.logout(); + sleepUntilUserDataRefreshed(); - assert.commandFailed(eventualDb.getSiblingDB("test").runCommand({find: "foo", batchSize: 0})); + assert(!eventualDb.auth("user12", "user")); } function testUsersInfoCommand(conn) { @@ -184,7 +203,7 @@ function testUsersInfoCommand(conn) { res.users.forEach(assertFun); } - var admin = conn.getDB("admin"); + const admin = conn.getDB("admin"); assert(admin.auth("admin", "admin")); assert.commandWorked(admin.runCommand({createUser: "user", pwd: "pwd", roles: []})); @@ -289,6 +308,8 @@ function testUsersInfoCommand(conn) { assert(userDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); assert.eq(1, userDoc["inheritedAuthenticationRestrictions"].length); }); + + admin.logout(); } function testRolesInfoCommand(conn) { @@ -299,7 +320,7 @@ function testRolesInfoCommand(conn) { res.roles.forEach(assertFun); } - var admin = conn.getDB("admin"); + const admin = conn.getDB("admin"); assert(admin.auth("admin", "admin")); assert.commandWorked(admin.runCommand({createRole: "role", roles: [], privileges: []})); @@ -358,24 +379,26 @@ function testRolesInfoCommand(conn) { assert(roleDoc.hasOwnProperty("inheritedAuthenticationRestrictions")); assert.eq(2, roleDoc.inheritedAuthenticationRestrictions.length); }); + + admin.logout(); } -var keyfile = "jstests/libs/key1"; +const keyfile = "jstests/libs/key1"; print("Testing standalone"); -var conn = MongoRunner.runMongod({bind_ip_all: "", auth: ""}); +const 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( +const rst = new ReplSetTest( {name: 'testset', nodes: 2, nodeOptions: {bind_ip_all: "", auth: ""}, keyFile: keyfile}); -var nodes = rst.startSet(); +const nodes = rst.startSet(); rst.initiate(); rst.awaitSecondaryNodes(); -var awaitReplication = function() { +const awaitReplication = function() { authutil.asCluster(nodes, "jstests/libs/key1", function() { rst.awaitReplication(); }); @@ -388,7 +411,7 @@ testRolesInfoCommand(rst.getPrimary()); rst.stopSet(); print("Testing sharded cluster"); -var st = new ShardingTest({ +const st = new ShardingTest({ mongos: 2, config: 3, shard: 1, diff --git a/jstests/auth/authz_cache_on_system_modification.js b/jstests/auth/authz_cache_on_system_modification.js index 02239019a85..23473cd0d01 100644 --- a/jstests/auth/authz_cache_on_system_modification.js +++ b/jstests/auth/authz_cache_on_system_modification.js @@ -28,6 +28,7 @@ assert.commandWorked(db.runCommand({ "Could not create custom role"); assert.commandWorked(db.runCommand({createUser: 'custom', pwd: 'pwd', roles: ['writeCustom']}), "Could not create new user with custom role"); +db.logout(); // tests that a user does not retain their privileges after the system.roles collection is modified (function testModifySystemRolesCollection() { @@ -35,14 +36,19 @@ assert.commandWorked(db.runCommand({createUser: 'custom', pwd: 'pwd', roles: ['w assert(db.auth('custom', 'pwd')); assert.commandWorked(db.runCommand({insert: "admin.test", documents: [{foo: "bar"}]}), "Could not insert to test collection with 'custom' user"); + db.logout(); + assert(db.auth('root', 'pwd')); assert.commandWorked(db.runCommand({renameCollection: "admin.system.roles", to: "admin.wolez"}), "Could not rename system.roles collection with root user"); + db.logout(); + assert(db.auth('custom', 'pwd')); assert.commandFailedWithCode( db.runCommand({insert: "admin.test", documents: [{woo: "mar"}]}), authzErrorCode, "Privileges retained after modification to system.roles collections"); + db.logout(); })(); // tests that a user does not retain their privileges after the system.users colleciton is modified @@ -57,7 +63,8 @@ assert.commandWorked(db.runCommand({createUser: 'custom', pwd: 'pwd', roles: ['w db.runCommand({renameCollection: 'admin.scratch', to: 'admin.system.users'}), authzErrorCode, "User cache not invalidated after modification to system collection"); + db.logout(); })(); MongoRunner.stopMongod(conn); -})();
\ No newline at end of file +})(); diff --git a/jstests/auth/basic_role_auth.js b/jstests/auth/basic_role_auth.js index b86f61dba9d..ac906d3fd98 100644 --- a/jstests/auth/basic_role_auth.js +++ b/jstests/auth/basic_role_auth.js @@ -434,6 +434,7 @@ var TESTS = [ test: function(conn) { var testDB = conn.getDB('test'); assert.eq(1, testDB.auth('rw', AUTH_INFO.test.rw.pwd)); + testDB.logout(); assert.eq(1, testDB.auth('ro', AUTH_INFO.test.ro.pwd)); testOps(testDB, READ_PERM); diff --git a/jstests/auth/clac_system_colls.js b/jstests/auth/clac_system_colls.js index 066b6e6c727..496a93c5344 100644 --- a/jstests/auth/clac_system_colls.js +++ b/jstests/auth/clac_system_colls.js @@ -26,6 +26,7 @@ function runTest(admindb) { admindb.createUser({user: "user", pwd: "pwd", roles: ["FindInDB"]}); // Verify the find on all collections exludes system collections + admindb.logout(); assert.eq(1, admindb.auth("user", "pwd")); assert.doesNotThrow(function() { @@ -36,6 +37,7 @@ function runTest(admindb) { } // Verify that find on system collections gives find permissions + admindb.logout(); assert.eq(1, admindb.auth("sysUser", "pwd")); assert.throws(function() { diff --git a/jstests/auth/cluster_ip_allowlist.js b/jstests/auth/cluster_ip_allowlist.js index 76ac47593d9..fbee89bbbb5 100644 --- a/jstests/auth/cluster_ip_allowlist.js +++ b/jstests/auth/cluster_ip_allowlist.js @@ -43,15 +43,16 @@ function testIpAllowlistRuntime(description, allowlistString, authResult) { print("Runtime: " + description); const conn = MongoRunner.runMongod({keyFile: "jstests/libs/key1"}); + const admin = conn.getDB('admin'); + const local = conn.getDB('local'); // Must create a user to verify that we don't fallback to localhost exception for auth. - assert.commandWorked( - conn.getDB('admin').runCommand({createUser: 'admin', pwd: 'admin', roles: ['root']})); + assert.commandWorked(admin.runCommand({createUser: 'admin', pwd: 'admin', roles: ['root']})); - assert.eq(true, conn.getDB("local").auth("__system", "foopdedoop")); + assert(local.auth("__system", "foopdedoop")); print("Testing whether __system can login after set to: " + allowlistString); - assert.commandWorked(conn.adminCommand( + assert.commandWorked(admin.runCommand( {setParameter: 1, "clusterIpSourceAllowlist": allowlistString.split(",")})); if (!authResult) { // At this time we have no valid authentication, and existing session should reset. @@ -60,18 +61,21 @@ function testIpAllowlistRuntime(description, allowlistString, authResult) { assert.commandFailed(conn.adminCommand({fsync: 1})); } - assert.eq(authResult, conn.getDB("local").auth("__system", "foopdedoop")); + let authDB = local; + assert.eq(authResult, local.auth("__system", "foopdedoop")); emitWarningAuthErrorIsExpected(authResult); if (!authResult) { print("Authenticating with admin user since __system is barred"); - conn.getDB('admin').auth('admin', 'admin'); + assert(admin.auth('admin', 'admin')); + authDB = admin; } print("Testing that __system can login after reset to null"); - assert.commandWorked(conn.adminCommand({setParameter: 1, "clusterIpSourceAllowlist": null})); - conn.getDB("local").logout(); - assert.eq(true, conn.getDB("local").auth("__system", "foopdedoop")); + assert.commandWorked(admin.runCommand({setParameter: 1, "clusterIpSourceAllowlist": null})); + authDB.logout(); + + assert.eq(true, local.auth("__system", "foopdedoop")); MongoRunner.stopMongod(conn); } diff --git a/jstests/auth/commands_user_defined_roles.js b/jstests/auth/commands_user_defined_roles.js index f214bddc9df..3c9b33cd54a 100644 --- a/jstests/auth/commands_user_defined_roles.js +++ b/jstests/auth/commands_user_defined_roles.js @@ -20,33 +20,39 @@ var testRole = "userDefinedRolesTestRole"; load("jstests/auth/lib/commands_lib.js"); load("jstests/libs/fail_point_util.js"); -/** - * Run the command specified in 't' with the privileges specified in 'privileges'. - */ -function testProperAuthorization(conn, t, testcase, privileges) { - var out = ""; +function doTestSetup(conn, t, testcase, privileges) { + const admin = conn.getDB('admin'); + const runOnDb = conn.getDB(testcase.runOnDb); + const state = authCommandsLib.setup(conn, t, runOnDb); - var runOnDb = conn.getDB(testcase.runOnDb); - var firstDb = conn.getDB(firstDbName); - var adminDb = conn.getDB(adminDbName); + assert(admin.auth('admin', 'password')); + assert.commandWorked(admin.runCommand({updateRole: testRole, privileges: privileges})); + admin.logout(); - var state = authCommandsLib.setup(conn, t, runOnDb); - - adminDb.auth("admin", "password"); - assert.commandWorked(adminDb.runCommand({updateRole: testRole, privileges: privileges})); - adminDb.logout(); + return state; +} - assert(adminDb.auth(testUser, "password")); +function doTestTeardown(conn, t, testcase, res) { + const runOnDb = conn.getDB(testcase.runOnDb); + authCommandsLib.teardown(conn, t, runOnDb, res); +} +/** + * Run the command specified in 't' with the privileges specified in 'privileges'. + */ +function testProperAuthorization(conn, t, testcase, privileges) { + const runOnDb = conn.getDB(testcase.runOnDb); + const state = doTestSetup(conn.sidechannel, t, testcase, privileges); authCommandsLib.authenticatedSetup(t, runOnDb); - var command = t.command; + let command = t.command; if (typeof (command) === "function") { command = t.command(state, testcase.commandArgs); } - var res = runOnDb.runCommand(command); + const res = runOnDb.runCommand(command); - if (!testcase.expectFail && res.ok != 1 && res.code != commandNotSupportedCode) { + let out = ""; + if (!testcase.expectFail && (res.ok != 1) && (res.code != commandNotSupportedCode)) { // don't error if the test failed with code commandNotSupported since // some storage engines don't support some commands. out = "command failed with " + tojson(res) + " on db " + testcase.runOnDb + @@ -57,47 +63,34 @@ function testProperAuthorization(conn, t, testcase, privileges) { tojson(privileges); } - firstDb.logout(); - authCommandsLib.teardown(conn, t, runOnDb, res); + doTestTeardown(conn.sidechannel, t, testcase, res); return out; } function testInsufficientPrivileges(conn, t, testcase, privileges) { - var out = ""; - - var runOnDb = conn.getDB(testcase.runOnDb); - var firstDb = conn.getDB(firstDbName); - var adminDb = conn.getDB(adminDbName); - - var state = authCommandsLib.setup(conn, t, runOnDb); - - adminDb.auth("admin", "password"); - assert.commandWorked(adminDb.runCommand({updateRole: testRole, privileges: privileges})); - adminDb.logout(); - - assert(adminDb.auth(testUser, "password")); - + const runOnDb = conn.getDB(testcase.runOnDb); + const state = doTestSetup(conn.sidechannel, t, testcase, privileges); authCommandsLib.authenticatedSetup(t, runOnDb); - var command = t.command; + let command = t.command; if (typeof (command) === "function") { command = t.command(state, testcase.commandArgs); } - var res = runOnDb.runCommand(command); + const res = runOnDb.runCommand(command); - if (res.ok == 1 || res.code != authErrCode) { + let out = ""; + if ((res.ok == 1) || (res.code != authErrCode)) { out = "expected authorization failure " + " but received " + tojson(res) + " with privileges " + tojson(privileges); } - firstDb.logout(); - authCommandsLib.teardown(conn, t, runOnDb); + doTestTeardown(conn.sidechannel, t, testcase, res); return out; } function runOneTest(conn, t) { - var failures = []; - var msg; + const failures = []; + let msg; // Some tests requires mongot, however, setting this failpoint will make search queries to // return EOF, that way all the hassle of setting it up can be avoided. @@ -106,8 +99,8 @@ function runOneTest(conn, t) { disableSearchFailpoint = configureFailPoint(conn.rs0 ? conn.rs0.getPrimary() : conn, 'searchReturnEofImmediately'); } - for (var i = 0; i < t.testcases.length; i++) { - var testcase = t.testcases[i]; + for (let i = 0; i < t.testcases.length; i++) { + const testcase = t.testcases[i]; if (!("privileges" in testcase)) { continue; } @@ -123,9 +116,9 @@ function runOneTest(conn, t) { if ((testcase.privileges.length == 1 && testcase.privileges[0].actions.length > 1) || testcase.privileges.length > 1) { for (var j = 0; j < testcase.privileges.length; j++) { - var p = testcase.privileges[j]; - var resource = p.resource; - var actions = p.actions; + const p = testcase.privileges[j]; + const resource = p.resource; + const actions = p.actions; // A particular privilege can explicitly specify that it should not be removed when // testing for authorization failure. This accommodates special-case behavior for @@ -134,8 +127,8 @@ function runOneTest(conn, t) { continue; } - for (var k = 0; k < actions.length; k++) { - var privDoc = {resource: resource, actions: [actions[k]]}; + for (let k = 0; k < actions.length; k++) { + const privDoc = {resource: resource, actions: [actions[k]]}; msg = testInsufficientPrivileges(conn, t, testcase, [privDoc]); if (msg) { failures.push(t.testname + ": " + msg); @@ -150,9 +143,10 @@ function runOneTest(conn, t) { failures.push(t.testname + ": " + msg); } - var specialResource = function(resource) { - if (!resource) + function specialResource(resource) { + if (!resource) { return true; + } // Tests which use {db: "local", collection: "oplog.rs"} will not work with // {db: "", collection: "oplog.rs"}. oplog.rs is special, and does not match with @@ -162,13 +156,13 @@ function runOneTest(conn, t) { // the same property as oplog.rs. return !resource.db || !resource.collection || resource.collection.startsWith("system.") || resource.db == "local"; - }; + } // Test for proper authorization with the test case's privileges where non-system // collections are modified to be the empty string. msg = testProperAuthorization(conn, t, testcase, testcase.privileges.map(function(priv) { // Make a copy of the privilege so as not to modify the original array. - var modifiedPrivilege = Object.extend({}, priv, true); + const modifiedPrivilege = Object.extend({}, priv, true); if (modifiedPrivilege.resource.collection && !specialResource(priv.resource)) { modifiedPrivilege.resource.collection = ""; } @@ -182,7 +176,7 @@ function runOneTest(conn, t) { // empty string. msg = testProperAuthorization(conn, t, testcase, testcase.privileges.map(function(priv) { // Make a copy of the privilege so as not to modify the original array. - var modifiedPrivilege = Object.extend({}, priv, true); + const modifiedPrivilege = Object.extend({}, priv, true); if (!specialResource(priv.resource)) { modifiedPrivilege.resource.db = ""; } @@ -201,8 +195,7 @@ function runOneTest(conn, t) { } function createUsers(conn) { - var adminDb = conn.getDB(adminDbName); - var firstDb = conn.getDB(firstDbName); + const adminDb = conn.getDB(adminDbName); adminDb.createUser({user: "admin", pwd: "password", roles: ["__system"]}); assert(adminDb.auth("admin", "password")); @@ -212,18 +205,41 @@ function createUsers(conn) { {createUser: testUser, pwd: "password", roles: [{role: testRole, db: adminDbName}]})); adminDb.logout(); + + // Primary connection will now act as test user only. + assert(adminDb.auth(testUser, "password")); } -var opts = {auth: "", enableExperimentalStorageDetailsCmd: ""}; -var impls = {createUsers: createUsers, runOneTest: runOneTest}; +const opts = { + auth: "", + enableExperimentalStorageDetailsCmd: "" +}; +const impls = { + createUsers: createUsers, + runOneTest: runOneTest +}; // run all tests standalone -var conn = MongoRunner.runMongod(opts); -authCommandsLib.runTests(conn, impls); -MongoRunner.stopMongod(conn); +{ + const conn = MongoRunner.runMongod(opts); + + // Create secondary connection to be intermittently authed + // with admin privileges for setup/teardown. + conn.sidechannel = new Mongo(conn.host); + authCommandsLib.runTests(conn, impls); + MongoRunner.stopMongod(conn); +} // run all tests sharded -conn = new ShardingTest( - {shards: 1, mongos: 1, config: 1, keyFile: "jstests/libs/key1", other: {shardOptions: opts}}); -authCommandsLib.runTests(conn, impls); -conn.stop(); +{ + const conn = new ShardingTest({ + shards: 1, + mongos: 1, + config: 1, + keyFile: "jstests/libs/key1", + other: {shardOptions: opts} + }); + conn.sidechannel = new Mongo(conn.s0.host); + authCommandsLib.runTests(conn, impls); + conn.stop(); +} diff --git a/jstests/auth/db_multiple_login.js b/jstests/auth/db_multiple_login.js index b4d46aeb9e9..7f399419bcb 100644 --- a/jstests/auth/db_multiple_login.js +++ b/jstests/auth/db_multiple_login.js @@ -1,31 +1,25 @@ -// Test the behavior when two users from the same database are authenticated serially on a single -// connection. Expected behavior is that the first user is implicitly logged out by the second -// authentication. -// -// Regression test for SERVER-8144. -var conn = MongoRunner.runMongod({auth: ""}); -var admin = conn.getDB("admin"); -var test = conn.getDB("test"); +// Test that only one user may be authenticated against the database at a time. -admin.createUser({user: 'admin', pwd: 'a', roles: jsTest.adminUserRoles}); -assert(admin.auth('admin', 'a')); -test.createUser({user: 'reader', pwd: 'a', roles: ["read"]}); -test.createUser({user: 'writer', pwd: 'a', roles: ["readWrite"]}); -admin.logout(); +(function() { +'use strict'; + +const conn = MongoRunner.runMongod({auth: ''}); +const admin = conn.getDB('admin'); +const test = conn.getDB('test'); -// Nothing logged in, can neither read nor write. -assert.writeError(test.docs.insert({value: 0})); -assert.throws(function() { - test.foo.findOne(); -}); +admin.createUser({user: 'admin', pwd: 'pwd', roles: jsTest.adminUserRoles}); +assert(admin.auth('admin', 'pwd')); +test.createUser({user: 'user', pwd: 'pwd', roles: ['readWrite']}); -// Writer logged in, can read and write. -test.auth('writer', 'a'); -assert.commandWorked(test.docs.insert({value: 1})); -test.foo.findOne(); +jsTest.log('Testing multi-auth'); +assert(!test.auth('user', 'pwd')); + +jsTest.log('Testing re-auth after logout'); +admin.logout(); +assert(test.auth('user', 'pwd')); +test.logout(); -// Reader logged in, replacing writer, can only read. -test.auth('reader', 'a'); -assert.writeError(test.docs.insert({value: 2})); -test.foo.findOne(); -MongoRunner.stopMongod(conn, null, {user: 'admin', pwd: 'a'}); +jsTest.log('Shutting down'); +assert(admin.auth('admin', 'pwd')); +MongoRunner.stopMongod(conn); +})(); diff --git a/jstests/auth/getMore.js b/jstests/auth/getMore.js index 83e427accd6..d7588d73dc6 100644 --- a/jstests/auth/getMore.js +++ b/jstests/auth/getMore.js @@ -7,8 +7,8 @@ TestData.disableImplicitSessions = true; function runTest(conn) { - let adminDB = conn.getDB("admin"); - let hello = adminDB.runCommand("hello"); + const adminDB = conn.getDB("admin"); + const hello = adminDB.runCommand("hello"); assert.commandWorked(hello); const isMongos = (hello.msg === "isdbgrid"); @@ -252,70 +252,15 @@ function runTest(conn) { 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"}); +const conn = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"}); runTest(conn); MongoRunner.stopMongod(conn); // Run the test on a sharded cluster. -let cluster = new ShardingTest( +const cluster = new ShardingTest( {shards: 1, mongos: 1, keyFile: "jstests/libs/key1", other: {shardOptions: {auth: ""}}}); runTest(cluster); cluster.stop(); diff --git a/jstests/auth/kill_cursors.js b/jstests/auth/kill_cursors.js index ee791320520..e4fdc181b69 100644 --- a/jstests/auth/kill_cursors.js +++ b/jstests/auth/kill_cursors.js @@ -13,51 +13,34 @@ function runTest(mongod) { * * @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 killUsers - Array of ['username', db] 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 tryKill(db, authUser, killUsers, shouldWork) { function doKill(extra) { // Create a cursor to be killed later. - loginAll(authUsers); - let cmd = {find: db.coll.getName(), batchSize: 2}; - Object.assign(cmd, extra); + assert(authUser[1].auth(authUser[0], 'pass')); + const cmd = Object.assign({find: db.coll.getName(), batchSize: 2}, 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"); - } + authUser[1].logout(); + + killUsers.forEach(function(killUser) { + assert(killUser[1].auth(killUser[0], 'pass')); + const cmd = db.runCommand({killCursors: db.coll.getName(), cursors: [id]}); + killUser[1].logout(); + + if (shouldWork) { + assert.commandWorked(cmd, "Unable to kill cursor"); + } else { + assert.commandFailed(cmd, "Should not have been able to kill cursor"); + } + }); } + // Run though create/kill with and without a session ID. 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==")}}); - } + doKill({lsid: {id: BinData(4, "QlLfPHTySm6tqfuV+EOsVA==")}}); } function trySelfKill(user) { @@ -105,57 +88,39 @@ function runTest(mongod) { // Create a collection with batchable data assert(testA.auth('user1', 'pass')); - assert(testB.auth('user3', 'pass')); - for (var i = 0; i < 101; ++i) { + for (let i = 0; i < 101; ++i) { assert.commandWorked(testA.coll.insert({_id: i})); - assert.commandWorked(testB.coll.insert({_id: i})); } testA.logout(); + + assert(testB.auth('user3', 'pass')); + for (let i = 0; i < 101; ++i) { + assert.commandWorked(testB.coll.insert({_id: i})); + } 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); + 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); + 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); // 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); + 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); } const mongod = MongoRunner.runMongod({auth: ""}); diff --git a/jstests/auth/list_all_sessions.js b/jstests/auth/list_all_sessions.js index 52b48825577..02d90c3d04e 100644 --- a/jstests/auth/list_all_sessions.js +++ b/jstests/auth/list_all_sessions.js @@ -38,6 +38,7 @@ function runListAllSessionsTest(mongod) { assertErrorCode(config.system.sessions, viewAdminPipeline, ErrorCodes.Unauthorized); // Ensure that the cache now contains the session and is visible by admin + admin.logout(); assert(admin.auth('admin', 'pass')); const resultArray = config.system.sessions diff --git a/jstests/auth/list_local_sessions_base.js b/jstests/auth/list_local_sessions_base.js index 1901bd50914..64d4a1b9b94 100644 --- a/jstests/auth/list_local_sessions_base.js +++ b/jstests/auth/list_local_sessions_base.js @@ -47,6 +47,7 @@ function runListLocalSessionsTest(mongod) { assert.eq(bsonWoCompare(resultArray, resultArrayMine), 0); // Ensure that changing users hides the session. + db.logout(); assert(db.auth('user2', 'pass')); const otherArray = assert.doesNotThrow(listLocalSessions).toArray(); assert.eq(otherArray.length, 0); diff --git a/jstests/auth/list_sessions.js b/jstests/auth/list_sessions.js index 291c1e1d050..13a546d7329 100644 --- a/jstests/auth/list_sessions.js +++ b/jstests/auth/list_sessions.js @@ -56,6 +56,7 @@ function runListSessionsTest(mongod) { assertErrorCode(admin.system.collections, pipeline, ErrorCodes.InvalidNamespace); // Ensure that changing users hides the session everwhere. + admin.logout(); assert(admin.auth('user2', 'pass')); assert.eq(listSessions().toArray().length, 0); diff --git a/jstests/auth/profile.js b/jstests/auth/profile.js index 3c88b37ad29..d6e388dff4a 100644 --- a/jstests/auth/profile.js +++ b/jstests/auth/profile.js @@ -1,11 +1,13 @@ // Check that username information gets recorded properly in profiler. // @tags: [requires_profiling] -var conn = MongoRunner.runMongod(); -var db1 = conn.getDB("profile-a"); -var db2 = db1.getSiblingDB("profile-b"); -var username = "user"; -db1.createUser({user: username, pwd: "password", roles: jsTest.basicUserRoles}); -db2.createUser({user: username, pwd: "password", roles: jsTest.basicUserRoles}); + +(function() { +'use strict'; + +const conn = MongoRunner.runMongod(); +const db = conn.getDB("profile"); +const username = "user"; +db.createUser({user: username, pwd: "password", roles: jsTest.basicUserRoles}); function lastOp(db) { return db.system.profile.find().sort({$natural: -1}).next(); @@ -15,39 +17,27 @@ function principalName(user, db) { return user + "@" + db.getName(); } -db1.setProfilingLevel(0); -db1.system.profile.drop(); -assert.eq(0, db1.system.profile.count()); - -db1.setProfilingLevel(2); - -db1.foo.findOne(); -var last = lastOp(db1); -assert.eq("", last.user); -assert.eq(0, last.allUsers.length); - -db1.auth(username, "password"); - -db1.foo.findOne(); -var last = lastOp(db1); -assert.eq(principalName(username, db1), last.user); -assert.eq(1, last.allUsers.length); -assert.eq(username, last.allUsers[0].user); -assert.eq(db1, last.allUsers[0].db); - -db2.auth(username, "password"); - -db1.foo.findOne(); -var last = lastOp(db1); -// Which user gets put in "user" and the ordering of users in "allUsers" is undefined. -assert((principalName(username, db1) == last.user) || (principalName(username, db2) == last.user)); -assert.eq(2, last.allUsers.length); -assert.eq(username, last.allUsers[0].user); -assert.eq(username, last.allUsers[1].user); -assert((db1 == last.allUsers[0].db && db2 == last.allUsers[1].db) || - (db2 == last.allUsers[0].db && db1 == last.allUsers[1].db)); - -db1.setProfilingLevel(0); -db1.dropDatabase(); -db2.dropDatabase(); +db.setProfilingLevel(0); +db.system.profile.drop(); +assert.eq(0, db.system.profile.count()); + +db.setProfilingLevel(2); + +db.foo.findOne(); +const last1 = lastOp(db); +assert.eq("", last1.user); +assert.eq(0, last1.allUsers.length); + +assert(db.auth(username, "password")); +db.foo.findOne(); +const last2 = lastOp(db); +assert.eq(principalName(username, db), last2.user); +assert.eq(1, last2.allUsers.length); +assert.eq(username, last2.allUsers[0].user); +assert.eq(db, last2.allUsers[0].db); +db.logout(); + +db.setProfilingLevel(0); +db.dropDatabase(); MongoRunner.stopMongod(conn); +})(); diff --git a/jstests/auth/pseudo_commands.js b/jstests/auth/pseudo_commands.js index 1802336c2e3..4615f6dba08 100644 --- a/jstests/auth/pseudo_commands.js +++ b/jstests/auth/pseudo_commands.js @@ -5,21 +5,24 @@ * @tags: [requires_sharding] */ +(function() { +'use strict'; + function runTest(conn) { - var authzErrorCode = 13; + const authzErrorCode = 13; conn.getDB('admin').createUser({user: 'admin', pwd: 'pwd', roles: ['root']}); - var adminConn = new Mongo(conn.host); - adminConn.getDB('admin').auth('admin', 'pwd'); - var admin = adminConn.getDB('admin'); + const adminConn = new Mongo(conn.host); + const admin = adminConn.getDB('admin'); + + assert(admin.auth('admin', 'pwd')); admin.createRole({role: 'myRole', roles: [], privileges: []}); admin.createUser({user: 'spencer', pwd: 'pwd', roles: ['myRole']}); + const arbitraryShard = admin.getSiblingDB("config").shards.findOne(); - var db = conn.getDB('admin'); - db.auth('admin', 'pwd'); - var arbitraryShard = db.getSiblingDB("config").shards.findOne(); - db.auth('spencer', 'pwd'); + const db = conn.getDB('admin'); + assert(db.auth('spencer', 'pwd')); /** * Tests that a single operation has the proper authorization. The operation is run by invoking @@ -30,7 +33,7 @@ function runTest(conn) { */ function testProperAuthorization(testFunc, roles, privilege) { // Test built-in roles first - for (role in roles) { + for (let role in roles) { admin.updateRole("myRole", {roles: [role]}); testFunc(roles[role]); } @@ -197,3 +200,4 @@ jsTest.log('Test sharding'); var st = new ShardingTest({shards: 2, config: 3, keyFile: 'jstests/libs/key1'}); runTest(st.s); st.stop(); +})(); diff --git a/jstests/auth/rename.js b/jstests/auth/rename.js index 4bc25d1053d..0db405d32db 100644 --- a/jstests/auth/rename.js +++ b/jstests/auth/rename.js @@ -3,18 +3,21 @@ // Multiple users cannot be authenticated on one connection within a session. TestData.disableImplicitSessions = true; -var m = MongoRunner.runMongod({auth: ""}); +(function() { +'use strict'; -var db1 = m.getDB("foo"); -var db2 = m.getDB("bar"); -var admin = m.getDB('admin'); +const m = MongoRunner.runMongod({auth: ""}); + +const db1 = m.getDB("foo"); +const db2 = m.getDB("bar"); +const admin = m.getDB('admin'); // Setup initial data admin.createUser({user: 'admin', pwd: 'password', roles: jsTest.adminUserRoles}); admin.auth('admin', 'password'); db1.createUser({user: "foo", pwd: "bar", roles: jsTest.basicUserRoles}); -db2.createUser({user: "bar", pwd: "foo", roles: jsTest.basicUserRoles}); +db2.createUser({user: "bar", pwd: "foo", roles: [{role: 'readWriteAnyDatabase', db: 'admin'}]}); printjson(db1.a.count()); db1.a.save({}); @@ -27,16 +30,17 @@ assert.commandFailed( admin.runCommand({renameCollection: db1.a.getFullName(), to: db1.b.getFullName()})); // can run same db with auth -db1.auth('foo', 'bar'); +assert(db1.auth('foo', 'bar')); assert.commandWorked( admin.runCommand({renameCollection: db1.a.getFullName(), to: db1.b.getFullName()})); // can't run diff db w/o auth assert.commandFailed( admin.runCommand({renameCollection: db1.b.getFullName(), to: db2.a.getFullName()})); +db1.logout(); // can run diff db with auth -db2.auth('bar', 'foo'); +assert(db2.auth('bar', 'foo')); assert.commandWorked( admin.runCommand({renameCollection: db1.b.getFullName(), to: db2.a.getFullName()})); @@ -44,5 +48,8 @@ assert.commandWorked( assert.eq(db1.a.count(), 0); assert.eq(db1.b.count(), 0); assert.eq(db2.a.count(), 1); +db2.logout(); -MongoRunner.stopMongod(m, null, {user: 'admin', pwd: 'password'}); +assert(admin.auth('admin', 'password')); +MongoRunner.stopMongod(m); +})(); diff --git a/jstests/auth/renameRestrictedCollections.js b/jstests/auth/renameRestrictedCollections.js index 6120d5c964a..4d487d38d08 100644 --- a/jstests/auth/renameRestrictedCollections.js +++ b/jstests/auth/renameRestrictedCollections.js @@ -19,7 +19,7 @@ const backdoorUserDoc = { adminDB.createUser({user: 'userAdmin', pwd: 'password', roles: ['userAdminAnyDatabase']}); -adminDB.auth('userAdmin', 'password'); +assert(adminDB.auth('userAdmin', 'password')); adminDB.createUser({user: 'readWriteAdmin', pwd: 'password', roles: ['readWriteAnyDatabase']}); adminDB.createUser({ user: 'readWriteAndUserAdmin', @@ -31,8 +31,8 @@ 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(adminDB.auth('readWriteAdmin', 'password')); +let res = adminDB.system.profile.renameCollection("profile"); assert.eq(0, res.ok); assert.eq(CodeUnauthorized, res.code); @@ -51,13 +51,15 @@ adminDB.users.drop(); jsTestLog("Test that a userAdmin can't rename system.users without readWrite"); adminDB.logout(); -adminDB.auth('userAdmin', 'password'); + +assert(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.logout(); -adminDB.auth('readWriteAndUserAdmin', 'password'); +assert(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"); @@ -74,8 +76,9 @@ 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.logout(); -adminDB.auth('rootier', 'password'); +assert(adminDB.auth('rootier', 'password')); // Test permissions against the configDB and localDB @@ -102,13 +105,15 @@ 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); +adminDB.logout(); // Test renaming system.users collection with __system assert(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)); + // 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 b02fe7951e6..61aed0e8271 100644 --- a/jstests/auth/resource_pattern_matching.js +++ b/jstests/auth/resource_pattern_matching.js @@ -8,26 +8,33 @@ // authenticating as the __system user. TestData.disableImplicitSessions = true; +(function() { +'use strict'; + function setup_users(granter) { - var admindb = granter.getSiblingDB("admin"); - admindb.runCommand({ + const admin = granter.getSiblingDB("admin"); + assert.commandWorked(admin.runCommand({ createUser: "admin", pwd: "admin", roles: - ["userAdminAnyDatabase", "dbAdminAnyDatabase", "clusterAdmin", "readWriteAnyDatabase"] - }); - - admindb.auth("admin", "admin"); - - printjson(admindb.runCommand({createRole: "test_role", privileges: [], roles: []})); - - printjson(admindb.runCommand({createUser: "test_user", pwd: "password", roles: ["test_role"]})); + ["userAdminAnyDatabase", + "dbAdminAnyDatabase", + "clusterAdmin", + "readWriteAnyDatabase"] + })); + + assert(admin.auth("admin", "admin")); + printjson(admin.runCommand({createRole: "test_role", privileges: [], roles: []})); + printjson(admin.runCommand({createUser: "test_user", pwd: "password", roles: ["test_role"]})); + admin.logout(); } function setup_dbs_and_cols(db) { - var test_db_a = db.getSiblingDB("a"); - var test_db_b = db.getSiblingDB("b"); + const admin = db.getSiblingDB('admin'); + const test_db_a = db.getSiblingDB('a'); + const test_db_b = db.getSiblingDB('b'); + assert(admin.auth('admin', 'admin')); assert.commandWorked(test_db_a.dropDatabase({w: 'majority'})); assert.commandWorked(test_db_b.dropDatabase({w: 'majority'})); @@ -36,45 +43,40 @@ function setup_dbs_and_cols(db) { assert.commandWorked(test_db_b.createCollection("a", {writeConcern: {w: 'majority'}})); assert.commandWorked(test_db_b.createCollection("b", {writeConcern: {w: 'majority'}})); + admin.logout(); } function grant_privileges(granter, privileges) { - var admindb = granter.getSiblingDB("admin"); + const admin = granter.getSiblingDB("admin"); - admindb.auth("admin", "admin"); - - var result = admindb.runCommand({ + assert(admin.auth("admin", "admin")); + const result = admin.runCommand({ grantPrivilegesToRole: "test_role", privileges: privileges, writeConcern: {w: 'majority'} }); - - admindb.logout(); - + admin.logout(); return result; } function revoke_privileges(granter, privileges) { - var admindb = granter.getSiblingDB("admin"); + const admin = granter.getSiblingDB("admin"); - admindb.auth("admin", "admin"); - - var result = admindb.runCommand({ + assert(admin.auth("admin", "admin")); + const result = admin.runCommand({ revokePrivilegesFromRole: "test_role", privileges: privileges, writeConcern: {w: 'majority'} }); - - admindb.logout(); - + admin.logout(); return result; } function invalidateUserCache(verifier) { - var admindb = verifier.getSiblingDB("admin"); - admindb.auth('admin', 'admin'); - admindb.runCommand("invalidateUserCache"); - admindb.logout(); + const admin = verifier.getSiblingDB("admin"); + assert(admin.auth('admin', 'admin')); + assert.commandWorked(admin.runCommand("invalidateUserCache")); + admin.logout(); } function run_test(name, granter, verifier, privileges, collections) { @@ -84,25 +86,24 @@ function run_test(name, granter, verifier, privileges, collections) { invalidateUserCache(verifier); const verifierDB = verifier.getSiblingDB('admin'); - verifierDB.auth("test_user", "password"); + assert(verifierDB.auth("test_user", "password")); for (var key in collections) { - var parts = key.split("."); - var testdb = verifier.getSiblingDB(parts[0]); - var col = testdb.getCollection(parts[1]); + const parts = key.split("."); + const testdb = verifier.getSiblingDB(parts[0]); + const col = testdb.getCollection(parts[1]); - var cb = collections[key]; + const cb = collections[key]; cb(testdb, col); } + verifierDB.logout(); revoke_privileges(granter, privileges); - verifierDB.logout(); } function run_test_bad_resource(name, granter, resource) { print("\n=== testing resource fail " + name + "() ===\n"); - var admindb = granter.getSiblingDB("admin"); assert.commandFailed(grant_privileges(granter, [{resource: resource, actions: ["find"]}])); } @@ -221,35 +222,45 @@ function run_tests(granter, verifier) { }); } -var keyfile = "jstests/libs/key1"; - -print('--- standalone node test ---'); -var conn = MongoRunner.runMongod({auth: null, keyFile: keyfile}); -run_tests(conn.getDB('test'), conn.getDB('test')); -MongoRunner.stopMongod(conn); -print('--- done standalone node test ---'); - -print('--- replica set test ---'); -var rst = - new ReplSetTest({name: 'testset', nodes: 2, nodeOptions: {'auth': null}, keyFile: keyfile}); - -rst.startSet(); -rst.initiate(); -var primary = rst.getPrimary().getDB('admin'); -rst.awaitSecondaryNodes(); -var secondary = rst.getSecondaries()[0].getDB('admin'); -run_tests(primary, secondary); -rst.stopSet(); -print('--- done with the rs tests ---'); - -print('--- sharding test ---'); -var st = new ShardingTest({ - mongos: 2, - shard: 1, - keyFile: keyfile, - other: - {mongosOptions: {'auth': null}, configOptions: {'auth': null}, shardOptions: {'auth': null}} -}); -run_tests(st.s0.getDB('admin'), st.s1.getDB('admin')); -st.stop(); -print('--- sharding test done ---'); +const keyfile = "jstests/libs/key1"; + +{ + print('--- standalone node test ---'); + const conn = MongoRunner.runMongod({auth: null, keyFile: keyfile}); + run_tests(conn.getDB('test'), conn.getDB('test')); + MongoRunner.stopMongod(conn); + print('--- done standalone node test ---'); +} + +{ + print('--- replica set test ---'); + const rst = + new ReplSetTest({name: 'testset', nodes: 2, nodeOptions: {'auth': null}, keyFile: keyfile}); + + rst.startSet(); + rst.initiate(); + const primary = rst.getPrimary().getDB('admin'); + rst.awaitSecondaryNodes(); + const secondary = rst.getSecondaries()[0].getDB('admin'); + run_tests(primary, secondary); + rst.stopSet(); + print('--- done with the rs tests ---'); +} + +{ + print('--- sharding test ---'); + const st = new ShardingTest({ + mongos: 2, + shard: 1, + keyFile: keyfile, + other: { + mongosOptions: {'auth': null}, + configOptions: {'auth': null}, + shardOptions: {'auth': null} + } + }); + run_tests(st.s0.getDB('admin'), st.s1.getDB('admin')); + st.stop(); + print('--- sharding test done ---'); +} +})(); diff --git a/jstests/auth/user_management_commands_lib.js b/jstests/auth/user_management_commands_lib.js index 128cdb300f8..859be7496d0 100644 --- a/jstests/auth/user_management_commands_lib.js +++ b/jstests/auth/user_management_commands_lib.js @@ -5,39 +5,42 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { 'use strict'; - var hasAuthzError = function(result) { + function hasAuthzError(result) { assert(result instanceof WriteCommandError); assert.eq(ErrorCodes.Unauthorized, result.code); - }; + } - conn.getDB('admin').createUser({user: 'admin', pwd: 'pwd', roles: ['root']}, writeConcern); - conn.getDB('admin').auth('admin', 'pwd'); - conn.getDB('admin').createUser({ + const admin = conn.getDB('admin'); + + admin.createUser({user: 'admin', pwd: 'pwd', roles: ['root']}, writeConcern); + assert(admin.auth('admin', 'pwd')); + admin.createUser({ user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase'], customData: {userAdmin: true} }, - writeConcern); - conn.getDB('admin').logout(); + writeConcern); + admin.logout(); - var userAdminConn = new Mongo(conn.host); - userAdminConn.getDB('admin').auth('userAdmin', 'pwd'); - var testUserAdmin = userAdminConn.getDB('test'); + const userAdminConn = new Mongo(conn.host); + const userAdmin = userAdminConn.getDB('admin'); + assert(userAdmin.auth('userAdmin', 'pwd')); + const testUserAdmin = userAdminConn.getDB('test'); testUserAdmin.createRole({ role: 'testRole', roles: [], privileges: [{resource: {db: 'test', collection: ''}, actions: ['viewRole']}], }, writeConcern); - userAdminConn.getDB('admin').createRole({ + userAdmin.createRole({ role: 'adminRole', roles: [], privileges: [{resource: {cluster: true}, actions: ['connPoolSync']}] }, - writeConcern); + writeConcern); - var db = conn.getDB('test'); + const db = conn.getDB('test'); // At this point there are 2 handles to the "test" database in use - "testUserAdmin" and "db". // "testUserAdmin" is on a connection which has been auth'd as a user with the @@ -58,7 +61,7 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { writeConcern); testUserAdmin.createUser({user: "andy", pwd: "pwd", roles: []}, writeConcern); - var user = testUserAdmin.getUser('spencer'); + const user = testUserAdmin.getUser('spencer'); assert.eq(10028, user.customData.zipCode); assert(db.auth('spencer', 'pwd')); assert.commandWorked(db.foo.insert({a: 1})); @@ -69,6 +72,7 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { assert.commandWorked(db.adminCommand('connPoolSync')); db.logout(); + assert(db.auth('andy', 'pwd')); hasAuthzError(db.foo.insert({a: 1})); assert.throws(function() { @@ -77,20 +81,21 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { assert.throws(function() { db.getRole('testRole'); }); + db.logout(); })(); (function testUpdateUser() { jsTestLog("Testing updateUser"); testUserAdmin.updateUser('spencer', {pwd: 'password', customData: {}}, writeConcern); - var user = testUserAdmin.getUser('spencer'); - assert.eq(null, user.customData.zipCode); + const user1 = testUserAdmin.getUser('spencer'); + assert.eq(null, user1.customData.zipCode); assert(!db.auth('spencer', 'pwd')); assert(db.auth('spencer', 'password')); testUserAdmin.updateUser( 'spencer', {customData: {zipCode: 10036}, roles: ["read", "testRole"]}, writeConcern); - var user = testUserAdmin.getUser('spencer'); + const user = testUserAdmin.getUser('spencer'); assert.eq(10036, user.customData.zipCode); hasAuthzError(db.foo.insert({a: 1})); assert.eq(1, db.foo.findOne().a); @@ -217,7 +222,7 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { jsTestLog("Testing usersInfo"); jsTestLog("Running exact usersInfo with default options on username only"); - var res = testUserAdmin.runCommand({usersInfo: 'spencer'}); + let res = testUserAdmin.runCommand({usersInfo: 'spencer'}); printjson(res); assert.eq(1, res.users.length); assert.eq(10036, res.users[0].customData.zipCode); @@ -424,12 +429,14 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { jsTestLog("Testing dropUser"); assert(db.auth('spencer', 'password')); + db.logout(); assert(db.auth('andy', 'pwd')); testUserAdmin.dropUser('spencer', writeConcern); assert(!db.auth('spencer', 'password')); assert(db.auth('andy', 'pwd')); + db.logout(); assert.eq(1, testUserAdmin.getUsers().length); })(); @@ -439,6 +446,7 @@ function runAllUserManagementCommandsTests(conn, writeConcern) { assert.eq(1, testUserAdmin.getUsers().length); assert(db.auth('andy', 'pwd')); + db.logout(); testUserAdmin.dropAllUsers(writeConcern); diff --git a/jstests/auth/user_management_commands_mechanisms.js b/jstests/auth/user_management_commands_mechanisms.js index 98c806f194b..a1784b2d375 100644 --- a/jstests/auth/user_management_commands_mechanisms.js +++ b/jstests/auth/user_management_commands_mechanisms.js @@ -6,7 +6,6 @@ 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'); @@ -32,6 +31,7 @@ function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) { } } + assert(admin.auth('admin', 'pass')); 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); @@ -54,6 +54,7 @@ function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) { assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-1'), haveSCRAMSHA1); assert.eq(userInfoWithCredentials.users[0].mechanisms.includes('SCRAM-SHA-256'), haveSCRAMSHA256); + admin.logout(); if (haveSCRAMSHA1) { checkCredentialRecord(user.credentials['SCRAM-SHA-1'], 28, 24, 10000); @@ -70,45 +71,53 @@ function checkUser(userid, passwd, haveSCRAMSHA1, haveSCRAMSHA256) { admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); assert(admin.auth('admin', 'pass')); +function createUser(db, user) { + assert(admin.auth('admin', 'pass')); + db.createUser(user); + admin.logout(); +} + +function createUserThrows(db, user) { + assert(admin.auth('admin', 'pass')); + assert.throws(() => db.createUser(user)); + admin.logout(); +} + // Unknown mechanism. -assert.throws(function() { - test.createUser({ - user: 'shalala', - pwd: 'pass', - roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-1', 'SCRAM-SHA-LA-LA'], - }); +createUserThrows(test, { + 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}); +createUser(test, {user: 'user', pwd: 'pass', roles: jsTest.basicUserRoles}); checkUser('user', 'pass', true, true); // Request SHA1 only. -test.createUser( +createUser( + test, {user: 'sha1user', pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); checkUser('sha1user', 'pass', true, false); // Request SHA256 only. -test.createUser( +createUser( + test, {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: []}); -}); +createUserThrows(test, + {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'}); -}); +createUserThrows( + test, {user: 'user2', pwd: 'pass', roles: jsTest.basicUserRoles, passwordDisgestor: 'client'}); -test.createUser({ +createUser(test, { user: 'sha1user2', pwd: 'pass', roles: jsTest.basicUserRoles, @@ -117,47 +126,55 @@ test.createUser({ }); checkUser('sha1user2', 'pass', true, false); -assert.throws(function() { - test.createUser({ - user: 'sha256user2', - pwd: 'pass', - roles: jsTest.basicUserRoles, - mechanisms: ['SCRAM-SHA-256'], - passwordDigestor: 'client' - }); +createUserThrows(test, { + user: 'sha256user2', + pwd: 'pass', + roles: jsTest.basicUserRoles, + mechanisms: ['SCRAM-SHA-256'], + passwordDigestor: 'client' }); +function updateUser(db, user, props) { + assert(admin.auth('admin', 'pass')); + db.updateUser(user, props); + admin.logout(); +} + +function updateUserThrows(db, user, props) { + assert(admin.auth('admin', 'pass')); + assert.throws(() => db.updateUser(user, props)); + admin.logout(); +} + // Update original 1/256 user to just sha-1. -test.updateUser('user', {pwd: 'pass1', mechanisms: ['SCRAM-SHA-1']}); +updateUser(test, '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']}); +updateUser(test, 'user', {pwd: 'pass256', mechanisms: ['SCRAM-SHA-256']}); checkUser('user', 'pass256', false, true); // And back to (default) all. -test.updateUser('user', {pwd: 'passAll'}); +updateUser(test, 'user', {pwd: 'passAll'}); checkUser('user', 'passAll', true, true); // Trim out mechanisms without changing password. -test.updateUser('user', {mechanisms: ['SCRAM-SHA-256']}); +updateUser(test, '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']}); -}); +updateUserThrows(test, 'user', {mechanisms: ['SCRAM-SHA-1']}); // Fail when passing an empty mechanisms field. -assert.throws(function() { - test.updateUser('user', {pwd: 'passEmpty', mechanisms: []}); -}); +updateUserThrows(test, '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']}); +createUser( + test, {user: "\u2168", pwd: 'pass', roles: jsTest.basicUserRoles, mechanisms: ['SCRAM-SHA-1']}); checkUser("\u2168", 'pass', true, false); +assert(admin.auth('admin', 'pass')); + // Demonstrate that usersInfo returns all users with mechanisms lists const allUsersInfo = assert.commandWorked(test.runCommand({usersInfo: 1})); allUsersInfo.users.forEach(function(userObj) { @@ -195,22 +212,29 @@ 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); +function restartWithOneMech(mech) { + const sha1ok = (mech === 'SCRAM-SHA-1'); + const sha256ok = (mech === 'SCRAM-SHA-256'); + mongod = MongoRunner.runMongod({ + auth: "", + setParameter: "authenticationMechanisms=" + mech, + restart: mongod, + noCleanData: true + }); + + const test = mongod.getDB('test'); + assert.eq(test.auth("sha1user", "pass"), sha1ok); + if (sha1ok) { + test.logout(); + } + assert.eq(test.auth("sha256user", "pass"), sha256ok); + if (sha256ok) { + test.logout(); + } + assert(mongod.getDB('admin').auth('admin', 'pass')); + MongoRunner.stopMongod(mongod); +} + +restartWithOneMech('SCRAM-SHA-1'); +restartWithOneMech('SCRAM-SHA-256'); })(); diff --git a/jstests/auth/user_special_chars.js b/jstests/auth/user_special_chars.js index 6ee9371860c..23afa7f617a 100644 --- a/jstests/auth/user_special_chars.js +++ b/jstests/auth/user_special_chars.js @@ -48,17 +48,6 @@ var testUserAndDatabaseAtSymbolConflation = function() { assert.commandWorked(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()); - - assert(bcDB.auth('a', 'pass2')); - assert(cDB.auth('a@b', 'pass1')); - assert(cDB.logout()); - assert(bcDB.logout()); }; testUserAndDatabaseAtSymbolConflation(); diff --git a/jstests/auth/views_authz.js b/jstests/auth/views_authz.js index 25093191628..b74176ea52a 100644 --- a/jstests/auth/views_authz.js +++ b/jstests/auth/views_authz.js @@ -11,12 +11,12 @@ TestData.disableImplicitSessions = true; function runTest(conn) { // Create the admin user. - let adminDB = conn.getDB("admin"); + const adminDB = conn.getDB("admin"); assert.commandWorked(adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]})); - assert.eq(1, adminDB.auth("admin", "admin")); + assert(adminDB.auth("admin", "admin")); const viewsDBName = "views_authz"; - let viewsDB = adminDB.getSiblingDB(viewsDBName); + const viewsDB = adminDB.getSiblingDB(viewsDBName); viewsDB.dropAllUsers(); viewsDB.logout(); @@ -38,7 +38,7 @@ function runTest(conn) { viewsDB.runCommand({createUser: "viewUser", pwd: "pwd", roles: ["readWriteView"]})); adminDB.logout(); - assert.eq(1, viewsDB.auth("viewUser", "pwd")); + assert(viewsDB.auth("viewUser", "pwd")); const lookupStage = {$lookup: {from: "forbidden", localField: "x", foreignField: "x", as: "y"}}; const graphLookupStage = { @@ -104,6 +104,7 @@ function runTest(conn) { assert.commandFailedWithCode(viewsDB.runCommand({collMod: "view", viewOn: "other"}), ErrorCodes.InvalidOptions, "modified a view without having to specify 'pipeline'"); + viewsDB.logout(); // Create a view on a forbidden collection and populate it. assert.eq(1, adminDB.auth("admin", "admin")); @@ -115,25 +116,27 @@ function runTest(conn) { // 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(viewsDB.auth("viewUser", "pwd")); assert.commandFailedWithCode(viewsDB.runCommand({find: "forbidden"}), ErrorCodes.Unauthorized, "successfully performed a find on an unreadable namespace"); - let res = viewsDB.runCommand({find: "view2", batchSize: 1}); + const 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"); + viewsDB.logout(); } // Run the test on a standalone. -let mongod = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"}); +const mongod = MongoRunner.runMongod({auth: "", bind_ip: "127.0.0.1"}); runTest(mongod); MongoRunner.stopMongod(mongod); // Run the test on a sharded cluster. -let cluster = new ShardingTest( +const cluster = new ShardingTest( {shards: 1, mongos: 1, keyFile: "jstests/libs/key1", other: {shardOptions: {auth: ""}}}); runTest(cluster); cluster.stop(); diff --git a/jstests/core/user_management_helpers.js b/jstests/core/user_management_helpers.js index 4bd64d51864..b71752a2ac8 100644 --- a/jstests/core/user_management_helpers.js +++ b/jstests/core/user_management_helpers.js @@ -6,11 +6,14 @@ // requires_non_retryable_commands, // ] +(function() { +'use strict'; + // This test is a basic sanity check of the shell helpers for manipulating user objects // It is not a comprehensive test of the functionality of the user manipulation commands function assertHasRole(rolesArray, roleName, roleDB) { - for (i in rolesArray) { - var curRole = rolesArray[i]; + for (let i in rolesArray) { + const curRole = rolesArray[i]; if (curRole.role == roleName && curRole.db == roleDB) { return; } @@ -19,7 +22,6 @@ function assertHasRole(rolesArray, roleName, roleDB) { } function runTest(db) { - var db = db.getSiblingDB("user_management_helpers"); db.dropDatabase(); db.dropAllUsers(); @@ -27,12 +29,12 @@ function runTest(db) { db.createUser({user: "andy", pwd: "password", roles: ['readWrite']}); // Test getUser - var userObj = db.getUser('spencer'); + let userObj = db.getUser('spencer'); assert.eq(1, userObj.roles.length); assertHasRole(userObj.roles, "readWrite", db.getName()); // Test getUsers - var users = db.getUsers(); + let users = db.getUsers(); assert.eq(2, users.length); assert(users[0].user == 'spencer' || users[1].user == 'spencer'); assert(users[0].user == 'andy' || users[1].user == 'andy'); @@ -93,19 +95,7 @@ function runTest(db) { db.createUser({user: 'user1', pwd: 'x', roles: [], passwordDigestor: 'foo'}); }); db.createUser({user: 'user1', pwd: 'x', roles: [], passwordDigestor: "server"}); - - // Note that as of SERVER-32974, client-side digestion is only permitted under the SCRAM-SHA-1 - // mechanism. - db.createUser({ - user: 'user2', - pwd: 'x', - roles: [], - mechanisms: ['SCRAM-SHA-1'], - passwordDigestor: "client" - }); assert(db.auth('user1', 'x')); - assert(db.auth('user2', 'x')); - assert.throws(function() { db.updateUser('user1', {pwd: 'y', digestPassword: true}); }); @@ -115,10 +105,25 @@ function runTest(db) { assert.throws(function() { db.updateUser('user1', {pwd: 'y', passwordDigestor: 'foo'}); }); + + // Change password and reauth using new credentials. db.updateUser('user1', {pwd: 'y', passwordDigestor: 'server'}); - db.updateUser('user2', {pwd: 'y', mechanisms: ['SCRAM-SHA-1'], passwordDigestor: 'client'}); assert(db.auth('user1', 'y')); + db.logout(); + + // Note that as of SERVER-32974, client-side digestion is only permitted under the SCRAM-SHA-1 + // mechanism. + db.createUser({ + user: 'user2', + pwd: 'x', + roles: [], + mechanisms: ['SCRAM-SHA-1'], + passwordDigestor: "client" + }); + assert(db.auth('user2', 'x')); + db.updateUser('user2', {pwd: 'y', mechanisms: ['SCRAM-SHA-1'], passwordDigestor: 'client'}); assert(db.auth('user2', 'y')); + db.logout(); // Test createUser requires 'user' field assert.throws(function() { @@ -132,9 +137,10 @@ function runTest(db) { } try { - runTest(db); + runTest(db.getSiblingDB('user_management_helpers')); } catch (x) { // BF-836 Print current users on failure to aid debugging db.getSiblingDB('admin').system.users.find().forEach(printjson); throw x; } +})(); diff --git a/jstests/multiVersion/libs/multi_rs.js b/jstests/multiVersion/libs/multi_rs.js index 48d8f57bd2e..058f6e7c404 100644 --- a/jstests/multiVersion/libs/multi_rs.js +++ b/jstests/multiVersion/libs/multi_rs.js @@ -78,20 +78,21 @@ ReplSetTest.prototype.upgradeArbiters = function(options, user, pwd) { }; ReplSetTest.prototype.upgradePrimary = function(primary, options, user, pwd) { + function authNode(node) { + if (user !== undefined) { + assert(node.getDB('admin').auth(user, pwd)); + } else { + jsTest.authenticate(node); + } + } + // Merge new options into node settings. this.nodeOptions = mergeNodeOptions(this.nodeOptions, options); - jsTest.authenticate(primary); + authNode(primary); let oldPrimary = this.stepdown(primary); - this.waitForState(oldPrimary, ReplSetTest.State.SECONDARY); - - // stepping down the node can close the connection and lose the authentication state, so - // re-authenticate here before calling awaitNodesAgreeOnPrimary(). - if (user != undefined) { - oldPrimary.getDB('admin').auth(user, pwd); - } - jsTest.authenticate(oldPrimary); + this.waitForState(oldPrimary, ReplSetTest.State.SECONDARY, undefined, authNode); // waitForState() runs the logout command via asCluster() on either the current primary or the // first node in the replica set so we re-authenticate on all connections before calling @@ -105,10 +106,7 @@ ReplSetTest.prototype.upgradePrimary = function(primary, options, user, pwd) { continue; } - if (user != undefined) { - node.getDB('admin').auth(user, pwd); - } - jsTest.authenticate(node); + authNode(node); } this.awaitNodesAgreeOnPrimary(); @@ -126,7 +124,7 @@ ReplSetTest.prototype.upgradePrimary = function(primary, options, user, pwd) { }; ReplSetTest.prototype.upgradeNode = function(node, opts = {}, user, pwd) { - if (user != undefined) { + if (user !== undefined) { assert.eq(1, node.getDB("admin").auth(user, pwd)); } jsTest.authenticate(node); @@ -145,7 +143,7 @@ ReplSetTest.prototype.upgradeNode = function(node, opts = {}, user, pwd) { } var newNode = this.restart(node, opts); - if (user != undefined) { + if (user !== undefined) { newNode.getDB("admin").auth(user, pwd); } @@ -153,6 +151,10 @@ ReplSetTest.prototype.upgradeNode = function(node, opts = {}, user, pwd) { [ReplSetTest.State.PRIMARY, ReplSetTest.State.SECONDARY, ReplSetTest.State.ARBITER]; this.waitForState(newNode, waitForStates); + if (user !== undefined) { + newNode.getDB('admin').logout(); + } + return newNode; }; diff --git a/jstests/noPassthrough/change_streams_required_privileges.js b/jstests/noPassthrough/change_streams_required_privileges.js index 2beae275bcc..504b641e68d 100644 --- a/jstests/noPassthrough/change_streams_required_privileges.js +++ b/jstests/noPassthrough/change_streams_required_privileges.js @@ -136,9 +136,12 @@ const adminDB = db.getSiblingDB("admin"); roles: [], privileges: [{resource: {cluster: true}, actions: ["changeStream"]}] }); + adminDB.logout(); }()); (function createUsers() { + assert(adminDB.auth("userAdmin", password)); + // Create some users for a specific collection. Use the name of the role as the name of the // user. for (let role of ["write", "find_only", "find_and_change_stream", "change_stream_only"]) { @@ -177,6 +180,8 @@ const adminDB = db.getSiblingDB("admin"); "cluster_change_stream_only"]) { adminDB.createUser({user: role, pwd: password, roles: [role]}); } + + adminDB.logout(); }()); (function testPrivilegesForSingleCollection() { diff --git a/jstests/noPassthrough/multi_user_forbidden.js b/jstests/noPassthrough/multi_user_forbidden.js index 33e6d7ca87f..e025c08b245 100644 --- a/jstests/noPassthrough/multi_user_forbidden.js +++ b/jstests/noPassthrough/multi_user_forbidden.js @@ -28,10 +28,12 @@ function runTest(conn) { const vanillaConn = new Mongo(conn.host); assert(vanillaConn.getDB(db1).auth(user1, pass), "Initial authN should succeed"); - assert(vanillaConn.getDB(db2).auth(user2, pass), "AuthN on another db should succeed"); + assert(!vanillaConn.getDB(db2).auth(user2, pass), "AuthN on another db should not succeed"); assert(vanillaConn.getDB(db1).auth(user1, pass), "Re-authN as first user should succeed"); - assert(vanillaConn.getDB(db3).auth(user3, pass), - "AuthN as a new user on the first database should succeed"); + assert(!vanillaConn.getDB(db3).auth(user3, pass), + "AuthN as a new user on the first database should not succeed"); + + vanillaConn.getDB(db1).logout(); } { @@ -39,10 +41,12 @@ function runTest(conn) { const laxConn = new Mongo(conn.host, undefined, {api: {version: '1', strict: false}}); assert(laxConn.getDB(db1).auth(user1, pass), "Initial authN should succeed"); - assert(laxConn.getDB(db2).auth(user2, pass), "AuthN on another db should succeed"); + assert(!laxConn.getDB(db2).auth(user2, pass), "AuthN on another db should not succeed"); assert(laxConn.getDB(db1).auth(user1, pass), "Re-authN as first user should succeed"); - assert(laxConn.getDB(db3).auth(user3, pass), - "AuthN as a new user on the first database should succeed"); + assert(!laxConn.getDB(db3).auth(user3, pass), + "AuthN as a new user on the first database should not succeed"); + + laxConn.getDB(db1).logout(); } { @@ -54,6 +58,8 @@ function runTest(conn) { assert(!strictConn.getDB(db1).auth(user1, pass), "Re-authN as first user should fail"); assert(!strictConn.getDB(db3).auth(user3, pass), "AuthN as a new user on the first database should fail"); + + strictConn.getDB(db1).logout(); } { @@ -64,11 +70,13 @@ function runTest(conn) { const strictishConn = new Mongo(conn.host, undefined, {api: {version: '1', strict: true}}); assert(strictishConn.getDB(db1).auth(user1, pass), "Initial authN should succeed"); - assert(strictishConn.getDB(db2).auth(user2, pass), "AuthN on another db should succeed"); + assert(!strictishConn.getDB(db2).auth(user2, pass), + "AuthN on another db should not succeed"); assert(strictishConn.getDB(db1).auth(user1, pass), "Re-authN as first user should succeed"); - assert(strictishConn.getDB(db3).auth(user3, pass), - "AuthN as a new user on the first database should succeed"); + assert(!strictishConn.getDB(db3).auth(user3, pass), + "AuthN as a new user on the first database should not succeed"); + strictishConn.getDB(db1).logout(); fp.off(); } } diff --git a/jstests/noPassthrough/start_session_command.js b/jstests/noPassthrough/start_session_command.js index 5c2bbd4b38b..0ad209c30e7 100644 --- a/jstests/noPassthrough/start_session_command.js +++ b/jstests/noPassthrough/start_session_command.js @@ -5,24 +5,20 @@ // implicit sessions. TestData.disableImplicitSessions = true; -var conn; -var admin; -var foo; -var result; const request = { startSession: 1 }; -conn = MongoRunner.runMongod({setParameter: {maxSessions: 2}}); -admin = conn.getDB("admin"); +let conn = MongoRunner.runMongod({setParameter: {maxSessions: 2}}); +let admin = conn.getDB("admin"); // ensure that the cache is empty -var serverStatus = assert.commandWorked(admin.adminCommand({serverStatus: 1})); +let serverStatus = assert.commandWorked(admin.adminCommand({serverStatus: 1})); assert.eq(0, serverStatus.logicalSessionRecordCache.activeSessionsCount); // test that we can run startSession unauthenticated when the server is running without --auth -result = admin.runCommand(request); +let result = admin.runCommand(request); assert.commandWorked( result, "failed test that we can run startSession unauthenticated when the server is running without --auth"); @@ -53,7 +49,6 @@ MongoRunner.stopMongod(conn); conn = MongoRunner.runMongod({auth: "", nojournal: ""}); admin = conn.getDB("admin"); -foo = conn.getDB("foo"); // test that we can't run startSession unauthenticated when the server is running with --auth @@ -66,8 +61,6 @@ assert.commandFailed( admin.createUser({user: 'admin', pwd: 'admin', roles: jsTest.adminUserRoles}); admin.auth("admin", "admin"); admin.createUser({user: 'user0', pwd: 'password', roles: jsTest.basicUserRoles}); -foo.createUser({user: 'user1', pwd: 'password', roles: jsTest.basicUserRoles}); -admin.createUser({user: 'user2', pwd: 'password', roles: []}); admin.logout(); // test that we can run startSession authenticated as one user with proper permissions @@ -79,21 +72,7 @@ assert.commandWorked( "failed test that we can run startSession authenticated as one user with proper permissions"); assert(result.id, "failed test that our session response has an id"); assert.eq(result.timeoutMinutes, 30, "failed test that our session record has the correct timeout"); - -// test that we cant run startSession authenticated as two users with proper permissions - -foo.auth("user1", "password"); -assert.commandFailed( - admin.runCommand(request), - "failed test that we cant run startSession authenticated as two users with proper permissions"); - -// test that we cant run startSession authenticated as one user without proper permissions - admin.logout(); -admin.auth("user2", "password"); -assert.commandFailed( - admin.runCommand(request), - "failed test that we cant run startSession authenticated as one user without proper permissions"); // diff --git a/jstests/replsets/advance_cluster_time.js b/jstests/replsets/advance_cluster_time.js index 86f1637acd7..2e4fdf74b15 100644 --- a/jstests/replsets/advance_cluster_time.js +++ b/jstests/replsets/advance_cluster_time.js @@ -54,6 +54,7 @@ function createUsers(primary) { pwd: kUserWithAdvanceClusterTimePrivilege.pwd, roles: [{role: "advanceClusterTimeRole", db: "admin"}, "readWrite"] })); + adminDB.logout(); } const rst1 = new ReplSetTest({ @@ -103,6 +104,9 @@ const rst2TestDB = rst2Primary.getDB(kDbName); assert.commandFailedWithCode( rst1TestDB.runCommand({find: kCollName, $clusterTime: rst2ClusterTime}), [ErrorCodes.TimeProofMismatch, ErrorCodes.KeyNotFound]); + + rst1TestDB.logout(); + rst2TestDB.logout(); })(); // Test clusterTime gossip when the client does have advanceClusterTime privilege. @@ -123,6 +127,9 @@ const rst2TestDB = rst2Primary.getDB(kDbName); jsTest.log("rst2's clusterTime " + tojson(rst2ClusterTime)); assert.commandWorked(rst1TestDB.runCommand({find: kCollName, $clusterTime: rst2ClusterTime})); + + rst1TestDB.logout(); + rst2TestDB.logout(); })(); rst1.stopSet(); diff --git a/jstests/replsets/auth1.js b/jstests/replsets/auth1.js index a91137391a8..14f213b96bd 100644 --- a/jstests/replsets/auth1.js +++ b/jstests/replsets/auth1.js @@ -105,6 +105,7 @@ print("unauthorized:"); printjson(primary.adminCommand({replSetGetStatus: 1})); doQueryOn(primary); +primary.getDB("admin").logout(); result = secondary.getDB("test").auth("bar", "baz"); assert.eq(result, 1); @@ -119,6 +120,7 @@ for (var i = 0; i < 1000; i++) { bulk.insert({x: i, foo: "bar"}); } assert.commandWorked(bulk.execute({w: 3, wtimeout: ReplSetTest.kDefaultTimeoutMS})); +primary.getDB("test").logout(); print("fail over"); rs.stop(mId); @@ -132,17 +134,21 @@ for (var i = 0; i < 1000; i++) { bulk.insert({x: i, foo: "bar"}); } assert.commandWorked(bulk.execute({w: 2})); +primary.getDB("test").logout(); print("resync"); rs.restart(mId, {"keyFile": key1_600}); +rs.keyFile = key1_600; primary = rs.getPrimary(); print("add some more data 2"); +primary.getDB("test").auth("bar", "baz"); bulk = primary.getDB("test").foo.initializeUnorderedBulkOp(); for (var i = 0; i < 1000; i++) { bulk.insert({x: i, foo: "bar"}); } bulk.execute({w: 3, wtimeout: ReplSetTest.kDefaultTimeoutMS}); +primary.getDB("test").logout(); print("add member with wrong key"); var conn = MongoRunner.runMongod({ @@ -162,6 +168,8 @@ try { } catch (e) { print("error: " + e); } +primary.getDB("admin").logout(); + primary = rs.getPrimary(); primary.getDB("admin").auth("foo", "bar"); @@ -173,6 +181,7 @@ for (var i = 0; i < 10; i++) { assert(results.members[3].state != 2); sleep(1000); } +primary.getDB("admin").logout(); print("stop member"); MongoRunner.stopMongod(conn); @@ -186,6 +195,7 @@ var conn = MongoRunner.runMongod({ keyFile: key1_600 }); +primary.getDB('admin').auth("foo", "bar"); wait(function() { try { var results = primary.adminCommand({replSetGetStatus: 1}); @@ -196,6 +206,7 @@ wait(function() { } return false; }); +primary.getDB('admin').logout(); print("make sure it has the config, too"); assert.soon(function() { @@ -203,6 +214,7 @@ assert.soon(function() { rs.nodes[i].setSecondaryOk(); rs.nodes[i].getDB("admin").auth("foo", "bar"); config = rs.nodes[i].getDB("local").system.replset.findOne(); + rs.nodes[i].getDB("admin").logout(); // We expect the config version to be 3 due to the initial config and then the // 'newlyAdded' removal reconfig. if (config.version !== 3) { diff --git a/jstests/replsets/rollback_auth.js b/jstests/replsets/rollback_auth.js index 6a4bb9ec392..5c08e4b3fae 100644 --- a/jstests/replsets/rollback_auth.js +++ b/jstests/replsets/rollback_auth.js @@ -17,22 +17,22 @@ TestData.disableImplicitSessions = true; // helper function for verifying contents at the end of the test -var checkFinalResults = function(db) { +function checkFinalResults(db) { assert.commandWorked(db.runCommand({dbStats: 1})); assert.commandFailedWithCode(db.runCommand({collStats: 'foo'}), authzErrorCode); assert.commandFailedWithCode(db.runCommand({collStats: 'bar'}), authzErrorCode); assert.commandWorked(db.runCommand({collStats: 'baz'})); assert.commandWorked(db.runCommand({collStats: 'foobar'})); -}; +} -var authzErrorCode = 13; +const authzErrorCode = 13; jsTestLog("Setting up replica set"); -var name = "rollbackAuth"; -var replTest = new ReplSetTest({name: name, nodes: 3, keyFile: 'jstests/libs/key1'}); -var nodes = replTest.nodeList(); -var conns = replTest.startSet(); +const name = "rollbackAuth"; +const replTest = new ReplSetTest({name: name, nodes: 3, keyFile: 'jstests/libs/key1'}); +const nodes = replTest.nodeList(); +const conns = replTest.startSet(); replTest.initiate({ "_id": "rollbackAuth", "members": [ @@ -44,41 +44,48 @@ replTest.initiate({ // Make sure we have a primary replTest.waitForState(replTest.nodes[0], ReplSetTest.State.PRIMARY); -var primary = replTest.getPrimary(); -var a_conn = conns[0]; -var b_conn = conns[1]; +const primary = replTest.getPrimary(); +const a_conn = conns[0]; +const b_conn = conns[1]; a_conn.setSecondaryOk(); b_conn.setSecondaryOk(); -var A = a_conn.getDB("admin"); -var B = b_conn.getDB("admin"); -var a = a_conn.getDB("test"); -var b = b_conn.getDB("test"); +const A_admin = a_conn.getDB("admin"); +const B_admin = b_conn.getDB("admin"); +const A_test = a_conn.getDB("test"); +const B_test = b_conn.getDB("test"); assert.eq(primary, conns[0], "conns[0] assumed to be primary"); assert.eq(a_conn, primary); // Make sure we have an arbiter assert.soon(function() { - var res = conns[2].getDB("admin").runCommand({replSetGetStatus: 1}); + const res = conns[2].getDB("admin").runCommand({replSetGetStatus: 1}); return res.myState == 7; }, "Arbiter failed to initialize."); jsTestLog("Creating initial data"); // Create collections that will be used in test -A.createUser({user: 'admin', pwd: 'pwd', roles: ['root']}); -A.auth('admin', 'pwd'); -a.foo.insert({a: 1}); -a.bar.insert({a: 1}); -a.baz.insert({a: 1}); -a.foobar.insert({a: 1}); +A_admin.createUser({user: 'admin', pwd: 'pwd', roles: ['root']}); +A_admin.auth('admin', 'pwd'); // Set up user admin user -A.createUser({user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase']}); -A.auth('userAdmin', 'pwd'); // Logs out of admin@admin user -B.auth('userAdmin', 'pwd'); +A_admin.createUser({user: 'userAdmin', pwd: 'pwd', roles: ['userAdminAnyDatabase']}); + +A_test.foo.insert({a: 1}); +A_test.bar.insert({a: 1}); +A_test.baz.insert({a: 1}); +A_test.foobar.insert({a: 1}); +A_admin.logout(); + +assert(A_admin.auth('userAdmin', 'pwd')); + +// Give replication time to catch up. +assert.soon(function() { + return B_admin.auth('userAdmin', 'pwd'); +}); // Create a basic user and role -A.createRole({ +A_admin.createRole({ role: 'replStatusRole', // To make awaitReplication() work roles: [], privileges: [ @@ -87,64 +94,75 @@ A.createRole({ {resource: {db: 'local', collection: 'system.replset'}, actions: ['find']} ] }); -a.createRole({ +A_test.createRole({ role: 'myRole', roles: [], privileges: [{resource: {db: 'test', collection: ''}, actions: ['dbStats']}] }); -a.createUser( +A_test.createUser( {user: 'spencer', pwd: 'pwd', roles: ['myRole', {role: 'replStatusRole', db: 'admin'}]}); -assert(a.auth('spencer', 'pwd')); + +A_admin.logout(); +B_admin.logout(); + +assert(A_test.auth('spencer', 'pwd')); // wait for secondary to get this data assert.soon(function() { - return b.auth('spencer', 'pwd'); + return B_test.auth('spencer', 'pwd'); }); -assert.commandWorked(a.runCommand({dbStats: 1})); -assert.commandFailedWithCode(a.runCommand({collStats: 'foo'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'bar'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'baz'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'foobar'}), authzErrorCode); +assert.commandWorked(A_test.runCommand({dbStats: 1})); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'foo'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'bar'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'baz'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'foobar'}), authzErrorCode); -assert.commandWorked(b.runCommand({dbStats: 1})); -assert.commandFailedWithCode(b.runCommand({collStats: 'foo'}), authzErrorCode); -assert.commandFailedWithCode(b.runCommand({collStats: 'bar'}), authzErrorCode); -assert.commandFailedWithCode(b.runCommand({collStats: 'baz'}), authzErrorCode); -assert.commandFailedWithCode(b.runCommand({collStats: 'foobar'}), authzErrorCode); +assert.commandWorked(B_test.runCommand({dbStats: 1})); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'foo'}), authzErrorCode); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'bar'}), authzErrorCode); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'baz'}), authzErrorCode); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'foobar'}), authzErrorCode); jsTestLog("Doing writes that will eventually be rolled back"); // down A and wait for B to become primary +A_test.logout(); replTest.stop(0); assert.soon(function() { try { - return B.hello().isWritablePrimary; + return B_admin.hello().isWritablePrimary; } catch (e) { return false; } }, "B didn't become primary"); -printjson(b.adminCommand('replSetGetStatus')); +printjson(assert.commandWorked(B_test.adminCommand('replSetGetStatus'))); +B_test.logout(); // Modify the the user and role in a way that will be rolled back. -b.grantPrivilegesToRole('myRole', - [{resource: {db: 'test', collection: 'foo'}, actions: ['collStats']}], - {}); // Default write concern will wait for majority, which will time out. -b.createRole({ +assert(B_admin.auth('admin', 'pwd')); +B_test.grantPrivilegesToRole( + 'myRole', + [{resource: {db: 'test', collection: 'foo'}, actions: ['collStats']}], + {}); // Default write concern will wait for majority, which will time out. +B_test.createRole({ role: 'temporaryRole', roles: [], privileges: [{resource: {db: 'test', collection: 'bar'}, actions: ['collStats']}] }, - {}); // Default write concern will wait for majority, which will time out. -b.grantRolesToUser('spencer', - ['temporaryRole'], - {}); // Default write concern will wait for majority, which will time out. + {}); // Default write concern will wait for majority, which will time out. +B_test.grantRolesToUser('spencer', + ['temporaryRole'], + {}); // Default write concern will wait for majority, which will time out. +B_admin.logout(); -assert.commandWorked(b.runCommand({dbStats: 1})); -assert.commandWorked(b.runCommand({collStats: 'foo'})); -assert.commandWorked(b.runCommand({collStats: 'bar'})); -assert.commandFailedWithCode(b.runCommand({collStats: 'baz'}), authzErrorCode); -assert.commandFailedWithCode(b.runCommand({collStats: 'foobar'}), authzErrorCode); +assert(B_test.auth('spencer', 'pwd')); +assert.commandWorked(B_test.runCommand({dbStats: 1})); +assert.commandWorked(B_test.runCommand({collStats: 'foo'})); +assert.commandWorked(B_test.runCommand({collStats: 'bar'})); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'baz'}), authzErrorCode); +assert.commandFailedWithCode(B_test.runCommand({collStats: 'foobar'}), authzErrorCode); +B_test.logout(); // down B, bring A back up, then wait for A to become primary // insert new data into A so that B will need to rollback when it reconnects to A @@ -153,39 +171,42 @@ replTest.stop(1); replTest.restart(0); assert.soon(function() { try { - return A.hello().isWritablePrimary; + return A_admin.hello().isWritablePrimary; } catch (e) { return false; } }, "A didn't become primary"); // A should not have the new data as it was down -assert.commandWorked(a.runCommand({dbStats: 1})); -assert.commandFailedWithCode(a.runCommand({collStats: 'foo'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'bar'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'baz'}), authzErrorCode); -assert.commandFailedWithCode(a.runCommand({collStats: 'foobar'}), authzErrorCode); +assert(A_test.auth('spencer', 'pwd')); +assert.commandWorked(A_test.runCommand({dbStats: 1})); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'foo'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'bar'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'baz'}), authzErrorCode); +assert.commandFailedWithCode(A_test.runCommand({collStats: 'foobar'}), authzErrorCode); +A_test.logout(); jsTestLog("Doing writes that should persist after the rollback"); // Modify the user and role in a way that will persist. -A.auth('userAdmin', 'pwd'); +A_admin.auth('userAdmin', 'pwd'); // Default write concern will wait for majority, which would time out // so we override it with an empty write concern -a.grantPrivilegesToRole( +A_test.grantPrivilegesToRole( 'myRole', [{resource: {db: 'test', collection: 'baz'}, actions: ['collStats']}], {}); -a.createRole({ +A_test.createRole({ role: 'persistentRole', roles: [], privileges: [{resource: {db: 'test', collection: 'foobar'}, actions: ['collStats']}] }, - {}); -a.grantRolesToUser('spencer', ['persistentRole'], {}); -A.logout(); -a.auth('spencer', 'pwd'); + {}); +A_test.grantRolesToUser('spencer', ['persistentRole'], {}); +A_admin.logout(); + +A_test.auth('spencer', 'pwd'); // A has the data we just wrote, but not what B wrote before -checkFinalResults(a); +checkFinalResults(A_test); jsTestLog("Triggering rollback"); @@ -197,11 +218,13 @@ assert.soonNoExcept(function() { replTest.awaitReplication(); }); - return b.auth('spencer', 'pwd'); + return B_test.auth('spencer', 'pwd'); }); // Now both A and B should agree -checkFinalResults(a); -checkFinalResults(b); +checkFinalResults(A_test); +checkFinalResults(B_test); + +A_test.logout(); // Verify data consistency between nodes. authutil.asCluster(replTest.nodes, 'jstests/libs/key1', function() { diff --git a/jstests/sharding/advance_cluster_time_action_type.js b/jstests/sharding/advance_cluster_time_action_type.js index ef739aa4b03..6cea1521e00 100644 --- a/jstests/sharding/advance_cluster_time_action_type.js +++ b/jstests/sharding/advance_cluster_time_action_type.js @@ -30,6 +30,7 @@ assert.commandWorked(testDB.runCommand({ pwd: 'pwd', roles: [{role: 'advanceClusterTimeRole', db: 'admin'}, 'readWrite'] })); +adminDB.logout(); assert.eq(1, testDB.auth("NotTrusted", "pwd")); let res = testDB.runCommand({insert: "foo", documents: [{_id: 0}]}); @@ -49,6 +50,7 @@ jsTestLog("running NonTrusted. command: " + tojson(cmdObj)); res = testDB.runCommand(cmdObj); assert.commandFailedWithCode( res, ErrorCodes.TimeProofMismatch, "Command request was: " + tojsononeline(cmdObj)); +testDB.logout(); assert.eq(1, testDB.auth("Trusted", "pwd")); jsTestLog("running Trusted. command: " + tojson(cmdObj)); diff --git a/jstests/sharding/authCommands.js b/jstests/sharding/authCommands.js index c82f3b77b19..7d78366b99e 100644 --- a/jstests/sharding/authCommands.js +++ b/jstests/sharding/authCommands.js @@ -282,6 +282,7 @@ checkWriteOps(false); // Authenticate as read-write user jsTestLog("Checking commands with read-write auth credentials"); +assert(testDB.logout().ok); assert(testDB.auth(rwUser, password)); checkReadOps(true); checkWriteOps(true); diff --git a/jstests/sharding/commands_that_write_accept_wc_configRS.js b/jstests/sharding/commands_that_write_accept_wc_configRS.js index 7b147aea257..c34b3d40d59 100644 --- a/jstests/sharding/commands_that_write_accept_wc_configRS.js +++ b/jstests/sharding/commands_that_write_accept_wc_configRS.js @@ -20,7 +20,7 @@ load('jstests/multiVersion/libs/auth_helpers.js'); // Multiple users cannot be authenticated on one connection within a session. TestData.disableImplicitSessions = true; -var st = new ShardingTest({ +const st = new ShardingTest({ // Set priority of secondaries to zero to prevent spurious elections. shards: { rs0: { @@ -36,45 +36,56 @@ var st = new ShardingTest({ mongos: 1 }); -var mongos = st.s; -var dbName = "wc-test-configRS"; -var db = mongos.getDB(dbName); -var adminDB = mongos.getDB('admin'); +const mongos = st.s; +const dbName = "wc-test-configRS"; +const adminDB = mongos.getDB('admin'); // A database connection on a local shard, rather than through the mongos. -var localDB = st.shard0.getDB('localWCTest'); -var collName = 'leaves'; -var coll = db[collName]; -var counter = 0; +const localDB = st.shard0.getDB('localWCTest'); -function dropTestData() { - st.configRS.awaitReplication(); - st.rs0.awaitReplication(); - st.rs1.awaitReplication(); - db.dropUser('username'); - db.dropUser('user1'); - localDB.dropUser('user2'); - assert(!db.auth("username", "password"), "auth should have failed"); - getNewDB(); -} +// Separate unauthenticated channel for use in confirmFunc(). +// The sharding_auth suite will stealth-authenticate us, +// using the local.__system account, so we must explicitly deauth. +// Since mongos has no 'local' database, we use the test-mode workaround +// via admin DB found in the implementation of the LogoutCommand. +const noauthConn = new Mongo(mongos.host); +noauthConn.getDB('admin').logout(); // We get new databases because we do not want to reuse dropped databases that may be in a // bad state. This test calls dropDatabase when config server secondary nodes are down, so the // command fails after only the database metadata is dropped from the config servers, but the // data on the shards still remains. This makes future operations, such as moveChunk, fail. +let db = mongos.getDB(dbName); +let noauthDB = noauthConn.getDB(dbName); +let counter = 0; +const collName = 'leaves'; +let coll = db[collName]; function getNewDB() { db = mongos.getDB(dbName + counter); + noauthDB = noauthConn.getDB(dbName + counter); counter++; coll = db[collName]; } +function dropTestData() { + st.configRS.awaitReplication(); + st.rs0.awaitReplication(); + st.rs1.awaitReplication(); + db.dropUser('username'); + db.dropUser('user1'); + localDB.dropUser('user2'); + assert(!noauthDB.auth("username", "password"), "auth should have failed"); + getNewDB(); +} + // Commands in 'commands' will accept any valid writeConcern. -var commands = []; +const commands = []; commands.push({ req: {createUser: 'username', pwd: 'password', roles: jsTest.basicUserRoles}, setupFunc: function() {}, confirmFunc: function() { - assert(db.auth("username", "password"), "auth failed"); + assert(noauthDB.auth("username", "password"), "auth failed"); + noauthDB.logout(); }, requiresMajority: true, runsOnShards: false, @@ -88,8 +99,9 @@ commands.push({ db.runCommand({createUser: 'username', pwd: 'password', roles: jsTest.basicUserRoles}); }, confirmFunc: function() { - assert(!db.auth("username", "password"), "auth should have failed"); - assert(db.auth("username", "password2"), "auth failed"); + assert(!noauthDB.auth("username", "password"), "auth should have failed"); + assert(noauthDB.auth("username", "password2"), "auth failed"); + noauthDB.logout(); }, requiresMajority: true, runsOnShards: false, @@ -99,11 +111,13 @@ commands.push({ commands.push({ req: {dropUser: 'tempUser'}, setupFunc: function() { - db.runCommand({createUser: 'tempUser', pwd: 'password', roles: jsTest.basicUserRoles}); - assert(db.auth("tempUser", "password"), "auth failed"); + assert.commandWorked( + db.runCommand({createUser: 'tempUser', pwd: 'password', roles: jsTest.basicUserRoles})); + assert(noauthDB.auth("tempUser", "password"), "auth failed"); + noauthDB.logout(); }, confirmFunc: function() { - assert(!db.auth("tempUser", "password"), "auth should have failed"); + assert(!noauthDB.auth("tempUser", "password"), "auth should have failed"); }, requiresMajority: true, runsOnShards: false, @@ -120,7 +134,7 @@ function testInvalidWriteConcern(wc, cmd) { dropTestData(); cmd.setupFunc(); - var res = runCommandCheckAdmin(db, cmd); + const res = runCommandCheckAdmin(db, cmd); assert.commandFailed(res); assert(!res.writeConcernError, 'bad writeConcern on config server had writeConcernError. ' + @@ -128,8 +142,6 @@ function testInvalidWriteConcern(wc, cmd) { } function runCommandFailOnShardsPassOnConfigs(cmd) { - var req = cmd.req; - var res; // This command is run on the shards in addition to the config servers. if (cmd.runsOnShards) { if (cmd.failsOnShards) { @@ -137,8 +149,8 @@ function runCommandFailOnShardsPassOnConfigs(cmd) { // We set the timeout high enough that the command should not time out against the // config server, but not exorbitantly high, because it will always time out against // shards and so will increase the runtime of this test. - req.writeConcern.wtimeout = 15 * 1000; - res = runCommandCheckAdmin(db, cmd); + cmd.req.writeConcern.wtimeout = 15 * 1000; + const res = runCommandCheckAdmin(db, cmd); restartReplicationOnAllShards(st); assert.commandFailed(res); assert(!res.writeConcernError, @@ -150,8 +162,8 @@ function runCommandFailOnShardsPassOnConfigs(cmd) { // We set the timeout high enough that the command should not time out against the // config server, but not exorbitantly high, because it will always time out against // shards and so will increase the runtime of this test. - req.writeConcern.wtimeout = 15 * 1000; - res = runCommandCheckAdmin(db, cmd); + cmd.req.writeConcern.wtimeout = 15 * 1000; + const res = runCommandCheckAdmin(db, cmd); restartReplicationOnAllShards(st); assert.commandWorked(res); cmd.confirmFunc(); @@ -160,7 +172,7 @@ function runCommandFailOnShardsPassOnConfigs(cmd) { } else { // This command is only run on the config servers and so should pass when shards are // not replicating. - res = runCommandCheckAdmin(db, cmd); + const res = runCommandCheckAdmin(db, cmd); restartReplicationOnAllShards(st); assert.commandWorked(res); cmd.confirmFunc(); @@ -171,25 +183,23 @@ function runCommandFailOnShardsPassOnConfigs(cmd) { } function testValidWriteConcern(wc, cmd) { - var req = cmd.req; - var setupFunc = cmd.setupFunc; - var confirmFunc = cmd.confirmFunc; - - req.writeConcern = wc; - jsTest.log("Testing " + tojson(req)); + cmd.req.writeConcern = wc; + jsTest.log("Testing " + tojson(cmd.req)); dropTestData(); - setupFunc(); + cmd.setupFunc(); // Command with a full cluster should succeed. - var res = runCommandCheckAdmin(db, cmd); + let res = runCommandCheckAdmin(db, cmd); assert.commandWorked(res); assert(!res.writeConcernError, 'command on a full cluster had writeConcernError: ' + tojson(res)); - confirmFunc(); + + cmd.confirmFunc(); dropTestData(); - setupFunc(); + cmd.setupFunc(); + // Stop replication at all shard secondaries. stopReplicationOnSecondariesOfAllShards(st); @@ -198,14 +208,15 @@ function testValidWriteConcern(wc, cmd) { runCommandFailOnShardsPassOnConfigs(cmd); dropTestData(); - setupFunc(); + cmd.setupFunc(); + // Stop replication at all config server secondaries and all shard secondaries. stopReplicationOnSecondariesOfAllShards(st); st.configRS.awaitReplication(); stopReplicationOnSecondaries(st.configRS, false /* changeReplicaSetDefaultWCToLocal */); // Command should fail after two config servers are not replicating. - req.writeConcern.wtimeout = 3000; + cmd.req.writeConcern.wtimeout = 3000; res = runCommandCheckAdmin(db, cmd); restartReplicationOnAllShards(st); assert.commandFailed(res); @@ -214,10 +225,13 @@ function testValidWriteConcern(wc, cmd) { 'command on config servers with a paused replicaset had writeConcernError: ' + tojson(res)); } -var majorityWC = {w: 'majority', wtimeout: ReplSetTest.kDefaultTimeoutMS}; +const majorityWC = { + w: 'majority', + wtimeout: ReplSetTest.kDefaultTimeoutMS +}; // Config server commands require w: majority writeConcerns. -var nonMajorityWCs = [{w: 'invalid'}, {w: 2}]; +const nonMajorityWCs = [{w: 'invalid'}, {w: 2}]; commands.forEach(function(cmd) { nonMajorityWCs.forEach(function(wc) { diff --git a/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js b/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js index 855cac557cd..77e5552ce7a 100644 --- a/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js +++ b/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js @@ -71,20 +71,16 @@ assert.commandWorked(admin.runCommand( {moveChunk: collSharded.toString(), find: {_id: -1}, to: st.shard0.shardName})); st.printShardingStatus(); -var shardedDBUser = "shardedDBUser"; -var unshardedDBUser = "unshardedDBUser"; +const dbUser = "dbUser"; jsTest.log("Setting up database users..."); -// Create db users -collSharded.getDB().createUser({user: shardedDBUser, pwd: password, roles: ["readWrite"]}); -collUnsharded.getDB().createUser({user: unshardedDBUser, pwd: password, roles: ["readWrite"]}); - +// Create db user +admin.createUser({user: dbUser, pwd: password, roles: ["readWriteAnyDatabase"]}); admin.logout(); function authDBUsers(conn) { - conn.getDB(collSharded.getDB().toString()).auth(shardedDBUser, password); - conn.getDB(collUnsharded.getDB().toString()).auth(unshardedDBUser, password); + assert(conn.getDB('admin').auth(dbUser, password)); return conn; } @@ -92,8 +88,7 @@ function authDBUsers(conn) { // is received, and refreshing requires communication with the primary to obtain the newest version. // Read from the secondaries once before taking down primaries to ensure they have loaded the // routing table into memory. -var mongosSetupConn = new Mongo(mongos.host); -authDBUsers(mongosSetupConn); +var mongosSetupConn = authDBUsers(new Mongo(mongos.host)); mongosSetupConn.setReadPref("secondary"); assert(!mongosSetupConn.getCollection(collSharded.toString()).find({}).hasNext()); @@ -106,7 +101,6 @@ gc(); // Clean up connections jsTest.log("Inserting initial data..."); var mongosConnActive = authDBUsers(new Mongo(mongos.host)); -authDBUsers(mongosConnActive); var mongosConnIdle = null; var mongosConnNew = null; diff --git a/jstests/sharding/query/aggregation_currentop.js b/jstests/sharding/query/aggregation_currentop.js index 0c9d1c3eb04..58d63128329 100644 --- a/jstests/sharding/query/aggregation_currentop.js +++ b/jstests/sharding/query/aggregation_currentop.js @@ -703,6 +703,7 @@ function runIdleSessionsTests(conn, adminDB, txnDB, useLocalOps) { ]) .itcount(), 0); + adminDB.logout(); // Cancel all transactions and close the associated sessions. for (let i in userNames) { @@ -714,6 +715,7 @@ function runIdleSessionsTests(conn, adminDB, txnDB, useLocalOps) { writeConcern: {w: 'majority'} })); sessions[i].endSession(); + adminDB.logout(); } } diff --git a/jstests/sharding/query/mrShardedOutputAuth.js b/jstests/sharding/query/mrShardedOutputAuth.js index 67e278d529d..2518bcc3095 100644 --- a/jstests/sharding/query/mrShardedOutputAuth.js +++ b/jstests/sharding/query/mrShardedOutputAuth.js @@ -12,22 +12,16 @@ const st = new ShardingTest( {name: "mrShardedOutputAuth", shards: 1, mongos: 1, other: {keyFile: 'jstests/libs/key1'}}); // Setup the users to the input, output and admin databases -const mongos = st.s; -let adminDb = mongos.getDB("admin"); -adminDb.createUser({user: "user", pwd: "pass", roles: jsTest.adminUserRoles}); +const authenticatedConn = st.s; +const adminDb = authenticatedConn.getDB('admin'); +adminDb.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); +assert(adminDb.auth('admin', 'pass')); -const authenticatedConn = new Mongo(mongos.host); -authenticatedConn.getDB('admin').auth("user", "pass"); -adminDb = authenticatedConn.getDB("admin"); assert.commandWorked(adminDb.adminCommand({enablesharding: "output"})); const configDb = authenticatedConn.getDB("config"); - const inputDb = authenticatedConn.getDB("input"); -inputDb.createUser({user: "user", pwd: "pass", roles: jsTest.basicUserRoles}); - const outputDb = authenticatedConn.getDB("output"); -outputDb.createUser({user: "user", pwd: "pass", roles: jsTest.basicUserRoles}); assert.commandWorked(adminDb.runCommand({enableSharding: outputDb.getName()})); const nDocs = 50; @@ -73,24 +67,23 @@ function assertFailure(cmdResponse, configDb, outputDb) { assert.eq(outputDb.numbers_out.count(), 0, "map/reduce should not have succeeded"); } +function runTest(user, roles, assertion) { + authenticatedConn.getDB(user.db).createUser({user: user.user, pwd: 'pass', roles: roles}); + + const conn = new Mongo(st.s.host); + assert(conn.getDB(user.db).auth(user.user, 'pass')); + const response = doMapReduce(conn, outputDb); + assertion(response, configDb, outputDb); +} + // Setup a connection authenticated to both input and output db -const inputOutputAuthConn = new Mongo(mongos.host); -inputOutputAuthConn.getDB('input').auth("user", "pass"); -inputOutputAuthConn.getDB('output').auth("user", "pass"); -let cmdResponse = doMapReduce(inputOutputAuthConn, outputDb); -assertSuccess(cmdResponse, configDb, outputDb); +runTest({user: 'inout', db: 'admin'}, ['readWriteAnyDatabase'], assertSuccess); // setup a connection authenticated to only input db -const inputAuthConn = new Mongo(mongos.host); -inputAuthConn.getDB('input').auth("user", "pass"); -cmdResponse = doMapReduce(inputAuthConn, outputDb); -assertFailure(cmdResponse, configDb, outputDb); +runTest({user: 'inonly', db: 'input'}, ['readWrite'], assertFailure); // setup a connection authenticated to only output db -const outputAuthConn = new Mongo(mongos.host); -outputAuthConn.getDB('output').auth("user", "pass"); -cmdResponse = doMapReduce(outputAuthConn, outputDb); -assertFailure(cmdResponse, configDb, outputDb); +runTest({user: 'outOnly', db: 'output'}, ['readWrite'], assertFailure); st.stop(); })(); diff --git a/jstests/ssl/auth-counters.js b/jstests/ssl/auth-counters.js index 04274ef8578..c8d762e7c5e 100644 --- a/jstests/ssl/auth-counters.js +++ b/jstests/ssl/auth-counters.js @@ -15,7 +15,7 @@ const admin = mongod.getDB('admin'); const external = mongod.getDB('$external'); admin.createUser({user: 'admin', pwd: 'pwd', roles: ['root']}); -admin.auth('admin', 'pwd'); +assert(admin.auth('admin', 'pwd')); const X509USER = 'CN=client,OU=KernelUser,O=MongoDB,L=New York City,ST=New York,C=US'; external.createUser({user: X509USER, roles: []}); @@ -24,10 +24,19 @@ external.createUser({user: X509USER, roles: []}); // For those, see jstests/auth/auth-counters.js const expected = assert.commandWorked(admin.runCommand({serverStatus: 1})) .security.authentication.mechanisms[x509]; +admin.logout(); + +function asAdmin(cmd, db = admin) { + // Does not interfere with stats since we only care about X509. + assert(admin.auth('admin', 'pwd')); + const result = assert.commandWorked(db.runCommand(cmd)); + admin.logout(); + return result; +} function assertStats() { - const mechStats = assert.commandWorked(admin.runCommand({serverStatus: 1})) - .security.authentication.mechanisms[x509]; + const mechStats = asAdmin({serverStatus: 1}).security.authentication.mechanisms[x509]; + try { assert.eq(mechStats.authenticate.received, expected.authenticate.received); assert.eq(mechStats.authenticate.successful, expected.authenticate.successful); @@ -90,11 +99,10 @@ assertSuccess({user: X509USER, mechanism: x509}); assertSuccessInternal(); // Fails once the user no longer exists. -external.dropUser(X509USER); +asAdmin({dropUser: X509USER}, external); assertFailure({mechanism: x509}); -const finalStats = - assert.commandWorked(admin.runCommand({serverStatus: 1})).security.authentication.mechanisms; +const finalStats = asAdmin({serverStatus: 1}).security.authentication.mechanisms; MongoRunner.stopMongod(mongod); printjson(finalStats); })(); diff --git a/jstests/sslSpecial/upgrade_to_x509_ssl_nossl.js b/jstests/sslSpecial/upgrade_to_x509_ssl_nossl.js index 7dca4147ab6..142b16bcabc 100644 --- a/jstests/sslSpecial/upgrade_to_x509_ssl_nossl.js +++ b/jstests/sslSpecial/upgrade_to_x509_ssl_nossl.js @@ -12,31 +12,23 @@ load("jstests/ssl/libs/ssl_helpers.js"); -function authAllNodes() { - for (var n = 0; n < rst.nodes.length; n++) { - var status = rst.nodes[n].getDB("admin").auth("root", "pwd"); - assert.eq(status, 1); - } -} +(function() { +'use strict'; // The mongo shell cannot authenticate as the internal __system user in tests that use x509 for // cluster authentication. Choosing the default value for wcMajorityJournalDefault in // ReplSetTest cannot be done automatically without the shell performing such authentication, so // in this test we must make the choice explicitly, based on the global test options. -var wcMajorityJournalDefault; -if (jsTestOptions().noJournal || jsTestOptions().storageEngine == "ephemeralForTest" || - jsTestOptions().storageEngine == "inMemory") { - wcMajorityJournalDefault = false; -} else { - wcMajorityJournalDefault = true; -} +const wcMajorityJournalDefault = !jsTestOptions().noJournal && + (jsTestOptions().storageEngine != "ephemeralForTest") && + (jsTestOptions().storageEngine != "inMemory"); -opts = { +const opts = { sslMode: "disabled", clusterAuthMode: "keyFile", }; -var NUM_NODES = 3; -var rst = new ReplSetTest( +const NUM_NODES = 3; +const rst = new ReplSetTest( {name: 'sslSet', nodes: NUM_NODES, waitForKeys: false, keyFile: KEYFILE, nodeOptions: opts}); rst.startSet(); @@ -45,16 +37,55 @@ rst.startSet(); rst.initiateWithAnyNodeAsPrimary(Object.extend( rst.getReplSetConfig(), {writeConcernMajorityJournalDefault: wcMajorityJournalDefault})); -// Connect to master and do some basic operations -var rstConn1 = rst.getPrimary(); -rstConn1.getDB("admin").createUser({user: "root", pwd: "pwd", roles: ["root"]}, {w: NUM_NODES}); -rstConn1.getDB("admin").auth("root", "pwd"); -rstConn1.getDB("test").a.insert({a: 1, str: "TESTTESTTEST"}); -assert.eq(1, rstConn1.getDB("test").a.find().itcount(), "Error interacting with replSet"); +// Make administrative user other than local.__system +rst.getPrimary().getDB("admin").createUser({user: "root", pwd: "pwd", roles: ["root"]}, + {w: NUM_NODES}); + +let entriesWritten = 0; +function testWrite(str) { + const entry = ++entriesWritten; + + const conn = rst.getPrimary(); + assert(conn.getDB('admin').auth('root', 'pwd')); + const test = conn.getDB('test'); + assert.writeOK(test.a.insert({a: entry, str: str})); + assert.eq(entry, test.a.find().itcount(), "Error interacting with replSet"); +} + +function authAllNodes(nodes) { + for (let n = 0; n < nodes.length; n++) { + assert(rst.nodes[n].getDB("admin").auth("root", "pwd")); + } +} + +function upgradeAndWrite(newOpts, str) { + authAllNodes(rst.nodes); + rst.upgradeSet(newOpts, 'root', 'pwd'); + authAllNodes(rst.nodes); + rst.awaitReplication(); + testWrite(str); +} + +function upgradeWriteAndConnect(newOpts, str) { + upgradeAndWrite(newOpts, str); + + assert.eq(0, + runMongoProgram("mongo", + "--port", + rst.ports[0], + "--ssl", + "--sslAllowInvalidCertificates", + "--sslPEMKeyFile", + CLIENT_CERT, + "--eval", + ";"), + "SSL Connection attempt failed when it should succeed"); +} -print("===== UPGRADE disabled,keyFile -> allowSSL,sendKeyfile ====="); -authAllNodes(); -rst.upgradeSet({ +testWrite(rst.getPrimary(), 'TESTTESTTEST'); + +jsTest.log("===== UPGRADE disabled,keyFile -> allowSSL,sendKeyfile ====="); +upgradeAndWrite({ sslMode: "allowSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: "", @@ -62,17 +93,10 @@ rst.upgradeSet({ keyFile: KEYFILE, sslCAFile: CA_CERT }, - "root", - "pwd"); -authAllNodes(); -rst.awaitReplication(); - -var rstConn2 = rst.getPrimary(); -rstConn2.getDB("test").a.insert({a: 2, str: "CHECKCHECKCHECK"}); -assert.eq(2, rstConn2.getDB("test").a.find().itcount(), "Error interacting with replSet"); + 'CHECKCHECKCHECK'); -print("===== UPGRADE allowSSL,sendKeyfile -> preferSSL,sendX509 ====="); -rst.upgradeSet({ +jsTest.log("===== UPGRADE allowSSL,sendKeyfile -> preferSSL,sendX509 ====="); +upgradeWriteAndConnect({ sslMode: "preferSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: "", @@ -80,29 +104,11 @@ rst.upgradeSet({ keyFile: KEYFILE, sslCAFile: CA_CERT }, - "root", - "pwd"); -authAllNodes(); -rst.awaitReplication(); - -var rstConn3 = rst.getPrimary(); -rstConn3.getDB("test").a.insert({a: 3, str: "PEASandCARROTS"}); -assert.eq(3, rstConn3.getDB("test").a.find().itcount(), "Error interacting with replSet"); - -var canConnectSSL = runMongoProgram("mongo", - "--port", - rst.ports[0], - "--ssl", - "--sslAllowInvalidCertificates", - "--sslPEMKeyFile", - CLIENT_CERT, - "--eval", - ";"); -assert.eq(0, canConnectSSL, "SSL Connection attempt failed when it should succeed"); - -print("===== UPGRADE preferSSL,sendX509 -> preferSSL,x509 ====="); + 'PEASandCARROTS'); + +jsTest.log("===== UPGRADE preferSSL,sendX509 -> preferSSL,x509 ====="); // we cannot upgrade past preferSSL here because it will break the test client -rst.upgradeSet({ +upgradeWriteAndConnect({ sslMode: "preferSSL", sslPEMKeyFile: SERVER_CERT, sslAllowInvalidCertificates: "", @@ -110,24 +116,7 @@ rst.upgradeSet({ keyFile: KEYFILE, sslCAFile: CA_CERT }, - "root", - "pwd"); -authAllNodes(); -rst.awaitReplication(); -var rstConn4 = rst.getPrimary(); -rstConn4.getDB("test").a.insert({a: 4, str: "BEEP BOOP"}); -rst.awaitReplication(); -assert.eq(4, rstConn4.getDB("test").a.find().itcount(), "Error interacting with replSet"); - -// Test that an ssl connection can still be made -var canConnectSSL = runMongoProgram("mongo", - "--port", - rst.ports[0], - "--ssl", - "--sslAllowInvalidCertificates", - "--sslPEMKeyFile", - CLIENT_CERT, - "--eval", - ";"); -assert.eq(0, canConnectSSL, "SSL Connection attempt failed when it should succeed"); + 'BEEP BOOP'); + rst.stopSet(); +})(); diff --git a/jstests/ssl_x509/upgrade_noauth_to_x509_ssl.js b/jstests/ssl_x509/upgrade_noauth_to_x509_ssl.js index 17b6ab30f21..33513246931 100644 --- a/jstests/ssl_x509/upgrade_noauth_to_x509_ssl.js +++ b/jstests/ssl_x509/upgrade_noauth_to_x509_ssl.js @@ -12,6 +12,8 @@ load('jstests/ssl/libs/ssl_helpers.js'); +TestData.disableImplicitSessions = true; + (function() { 'use strict'; var dbName = 'upgradeToX509'; @@ -47,10 +49,15 @@ assert.commandWorked(testDB.a.insert({a: 1, str: 'TESTTESTTEST'})); assert.eq(2, testDB.a.count(), 'Error interacting with replSet'); print('=== UPGRADE transition to x509/preferSSL -> x509/requireSSL ==='); + +// Pre-logout so that upgradeSet() can authenticate for itself. +rst.nodes.forEach((node) => node.getDB('admin').logout()); rst.upgradeSet(x509RequireSSL, 'root', 'root'); -// upgradeSet leaves its connections logged in as root -testDB = rst.getPrimary().getDB(dbName); +// Reauth and commit one last write. +const finalPrimary = rst.getPrimary(); +assert(finalPrimary.getDB('admin').auth('root', 'root')); +testDB = finalPrimary.getDB(dbName); assert.commandWorked(testDB.a.insert({a: 1, str: 'TESTTESTTEST'})); assert.eq(3, testDB.a.count(), 'Error interacting with replSet'); diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp index 70fa0e11309..8c2be85d37c 100644 --- a/src/mongo/db/auth/authorization_session_impl.cpp +++ b/src/mongo/db/auth/authorization_session_impl.cpp @@ -206,40 +206,29 @@ Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx, // This is the first authentication. return; } + invariant(userCount == 1); - auto previousUser = _authenticatedUsers.lookupByDBName(userName.getDB()); - if (previousUser) { - const auto& previousUserName = previousUser->getName(); - if (previousUserName.getUser() == userName.getUser()) { - LOGV2_WARNING(5626700, - "Client has attempted to reauthenticate as a single user", - "user"_attr = userName); - } else { - LOGV2_WARNING(5626701, - "Client has attempted to authenticate as multiple users on the " - "same database", - "previousUser"_attr = previousUserName, - "user"_attr = userName); - } - } else { - LOGV2_WARNING(5626702, - "Client has attempted to authenticate on multiple databases", - "previousUsers"_attr = _authenticatedUsers.toBSON(), + auto previousUser = _authenticatedUsers.begin()->get()->getName(); + if (previousUser == userName) { + // Allow reauthenticating as the same user, but warn. + LOGV2_WARNING(5626700, + "Client has attempted to reauthenticate as a single user", "user"_attr = userName); - } - - const auto hasStrictAPI = APIParameters::get(opCtx).getAPIStrict().value_or(false); - if (!hasStrictAPI) { - // We're allowed to skip the uassert because we're not so strict. - return; - } - if (allowMultipleUsersWithApiStrict.shouldFail()) { - // We've explicitly allowed this for testing. - return; + // Strict API requires no reauth, even as same user, unless FP is enabled. + const bool hasStrictAPI = APIParameters::get(opCtx).getAPIStrict().value_or(false); + uassert(5626703, + "Each client connection may only be authenticated once", + !hasStrictAPI || allowMultipleUsersWithApiStrict.shouldFail()); + } else { + uassert(5626701, + str::stream() << "Each client connection may only be authenticated once. " + << "Previously authenticated as: " << previousUser, + previousUser.getDB() == userName.getDB()); + uasserted(5626702, + str::stream() << "Client has attempted to authenticate on multiple databases." + << "Already authenticated as: " << previousUser); } - - uasserted(5626703, "Each client connection may only be authenticated once"); }; // Check before we start to reveal as little as possible. Note that we do not need the lock @@ -394,6 +383,16 @@ RoleNameIterator AuthorizationSessionImpl::getAuthenticatedRoleNames() { void AuthorizationSessionImpl::grantInternalAuthorization(Client* client) { stdx::lock_guard<Client> lk(*client); + if (MONGO_unlikely(_authenticatedUsers.count() > 0)) { + invariant(_authenticatedUsers.count() == 1); + auto previousUser = _authenticatedUsers.begin()->get()->getName(); + uassert(ErrorCodes::Unauthorized, + str::stream() << "Unable to grant internal authorization, previously authorized as " + << previousUser.getUnambiguousName(), + previousUser == internalSecurity.getUser()->get()->getName()); + return; + } + _authenticatedUsers.add(*internalSecurity.getUser()); _updateInternalAuthorizationState(); } diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 51633ca828c..4ecb9cca692 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -116,6 +116,21 @@ public: authzSession->logoutAllDatabases(_client.get(), "Ending AuthorizationSessionTest"); } + Status createUser(const UserName& username, const std::vector<RoleName>& roles) { + BSONObjBuilder userDoc; + userDoc.append("_id", username.getUnambiguousName()); + username.appendToBSON(&userDoc); + userDoc.append("credentials", credentials); + + BSONArrayBuilder rolesBSON(userDoc.subarrayStart("roles")); + for (const auto& role : roles) { + role.serializeToBSON(&rolesBSON); + } + rolesBSON.doneFast(); + + return managerState->insertPrivilegeDocument(_opCtx.get(), userDoc.obj(), {}); + } + protected: FailureCapableAuthzManagerExternalStateMock* managerState; transport::TransportLayerMock transportLayer; @@ -157,6 +172,37 @@ const ResourcePattern otherProfileCollResource( const ResourcePattern thirdProfileCollResource( ResourcePattern::forExactNamespace(NamespaceString("third.system.profile"))); +TEST_F(AuthorizationSessionTest, MultiAuthSameUserAllowed) { + authzSession->startContractTracking(); + + ASSERT_OK(createUser({"user1", "test"}, {})); + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user1", "test"})); + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user1", "test"})); + authzSession->logoutAllDatabases(_client.get(), "Test finished"); +} + +TEST_F(AuthorizationSessionTest, MultiAuthSameDBDisallowed) { + authzSession->startContractTracking(); + + ASSERT_OK(createUser({"user1", "test"}, {})); + ASSERT_OK(createUser({"user2", "test"}, {})); + + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user1", "test"})); + ASSERT_NOT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user2", "test"})); + authzSession->logoutAllDatabases(_client.get(), "Test finished"); +} + +TEST_F(AuthorizationSessionTest, MultiAuthMultiDBDisallowed) { + authzSession->startContractTracking(); + + ASSERT_OK(createUser({"user", "test1"}, {})); + ASSERT_OK(createUser({"user", "test2"}, {})); + + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user", "test1"})); + ASSERT_NOT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), {"user", "test2"})); + authzSession->logoutAllDatabases(_client.get(), "Test finished"); +} + TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { authzSession->startContractTracking(); @@ -175,21 +221,7 @@ TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); // Add a user with readWrite and dbAdmin on the test DB - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWrite" - << "db" - << "test") - << BSON("role" - << "dbAdmin" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {{"readWrite", "test"}, {"dbAdmin", "test"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); ASSERT_TRUE( @@ -198,20 +230,10 @@ TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { authzSession->isAuthorizedForActionsOnResource(testDBResource, ActionType::dbStats)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); // Add an admin user with readWriteAnyDatabase - ASSERT_OK( - managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "admin" - << "db" - << "admin" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWriteAnyDatabase" - << "db" - << "admin"))), - BSONObj())); + ASSERT_OK(createUser({"admin", "admin"}, {{"readWriteAnyDatabase", "admin"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("admin", "admin"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( @@ -226,7 +248,6 @@ TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { ASSERT_TRUE( authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); - authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); ASSERT_TRUE( authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); ASSERT_TRUE( @@ -265,25 +286,8 @@ TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { // Add a user with doubled-up readWrite and single dbAdmin on the test DB - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWrite" - << "db" - << "test") - << BSON("role" - << "dbAdmin" - << "db" - << "test") - << BSON("role" - << "readWrite" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, + {{"readWrite", "test"}, {"dbAdmin", "test"}, {"readWrite", "test"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); ASSERT_TRUE( @@ -292,63 +296,15 @@ TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { authzSession->isAuthorizedForActionsOnResource(testDBResource, ActionType::dbStats)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "rw" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWrite" - << "db" - << "test") - << BSON("role" - << "dbAdmin" - << "db" - << "test"))), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "useradmin" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "userAdmin" - << "db" - << "test"))), - BSONObj())); - ASSERT_OK( - managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "rwany" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWriteAnyDatabase" - << "db" - << "admin") - << BSON("role" - << "dbAdminAnyDatabase" - << "db" - << "admin"))), - BSONObj())); - ASSERT_OK( - managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "useradminany" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "userAdminAnyDatabase" - << "db" - << "admin"))), - BSONObj())); + ASSERT_OK(createUser({"rw", "test"}, {{"readWrite", "test"}, {"dbAdmin", "test"}})); + ASSERT_OK(createUser({"useradmin", "test"}, {{"userAdmin", "test"}})); + ASSERT_OK(createUser({"rwany", "test"}, + {{"readWriteAnyDatabase", "admin"}, {"dbAdminAnyDatabase", "admin"}})); + ASSERT_OK(createUser({"useradminany", "test"}, {{"userAdminAnyDatabase", "admin"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("rwany", "test"))); @@ -364,8 +320,8 @@ TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); ASSERT_TRUE( authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); - // Logging in as useradminany@test implicitly logs out rwany@test. ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("useradminany", "test"))); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); @@ -379,8 +335,8 @@ TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); - // Logging in as rw@test implicitly logs out useradminany@test. ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("rw", "test"))); ASSERT_FALSE( @@ -395,9 +351,8 @@ TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); - - // Logging in as useradmin@test implicitly logs out rw@test. ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("useradmin", "test"))); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); @@ -411,21 +366,12 @@ TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, InvalidateUser) { // Add a readWrite user - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWrite" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {{"readWrite", "test"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); ASSERT_TRUE( @@ -442,17 +388,7 @@ TEST_F(AuthorizationSessionTest, InvalidateUser) { BSONObj(), BSONObj(), &ignored)); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "read" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {{"read", "test"}})); // Make sure that invalidating the user causes the session to reload its privileges. authzManager->invalidateUserByName(_opCtx.get(), user->getName()); @@ -478,21 +414,12 @@ TEST_F(AuthorizationSessionTest, InvalidateUser) { ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test"))); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { // Add a readWrite user - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "readWrite" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {{"readWrite", "test"}})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); ASSERT_TRUE( @@ -510,17 +437,7 @@ TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { BSONObj(), BSONObj(), &ignored)); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSON_ARRAY(BSON("role" - << "read" - << "db" - << "test"))), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {{"read", "test"}})); // Even though the user's privileges have been reduced, since we've configured user // document lookup to fail, the authz session should continue to use its known out-of-date @@ -540,6 +457,7 @@ TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); ASSERT_FALSE( authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, AcquireUserObtainsAndValidatesAuthenticationRestrictions) { @@ -574,6 +492,7 @@ TEST_F(AuthorizationSessionTest, AcquireUserObtainsAndValidatesAuthenticationRes SockAddr::create(clientSource, 5555, AF_UNSPEC), SockAddr::create(serverAddress, 27017, AF_UNSPEC))); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); }; auto assertFails = [this](StringData clientSource, StringData serverAddress) { @@ -1158,113 +1077,23 @@ TEST_F(AuthorizationSessionTest, } TEST_F(AuthorizationSessionTest, AuthorizedSessionIsNotCoauthorizedWithEmptyUserSet) { - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); std::vector<UserName> userSet; ASSERT_FALSE( authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end()))); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, AuthorizedSessionIsCoauthorizedWithEmptyUserSetWhenAuthIsDisabled) { authzManager->setAuthEnabled(false); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); - std::vector<UserName> userSet; - ASSERT_TRUE( - authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end()))); -} - -TEST_F(AuthorizationSessionTest, AuthorizedSessionIsCoauthorizedWithIntersectingUserSet) { - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "admin" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("admin", "test"))); - std::vector<UserName> userSet; - userSet.emplace_back("admin", "test"); - userSet.emplace_back("tess", "test"); - ASSERT_TRUE( - authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end()))); -} - -TEST_F(AuthorizationSessionTest, AuthorizedSessionIsNotCoauthorizedWithNonintersectingUserSet) { - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "admin" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("admin", "test"))); - std::vector<UserName> userSet; - userSet.emplace_back("tess", "test"); - ASSERT_FALSE( - authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end()))); -} - -TEST_F(AuthorizationSessionTest, - AuthorizedSessionIsCoauthorizedWithNonintersectingUserSetWhenAuthIsDisabled) { - authzManager->setAuthEnabled(false); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "spencer" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(_opCtx.get(), - BSON("user" - << "admin" - << "db" - << "test" - << "credentials" << credentials << "roles" - << BSONArray()), - BSONObj())); + ASSERT_OK(createUser({"spencer", "test"}, {})); ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test"))); - ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("admin", "test"))); std::vector<UserName> userSet; - userSet.emplace_back("tess", "test"); ASSERT_TRUE( authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end()))); + authzSession->logoutDatabase(_client.get(), "test", "Kill the test!"); } TEST_F(AuthorizationSessionTest, CannotListCollectionsWithoutListCollectionsPrivilege) { @@ -1661,6 +1490,8 @@ TEST_F(AuthorizationSessionTest, MayBypassWriteBlockingModeIsSetCorrectly) { << "db" << "admin"))), BSONObj())); + authzSession->logoutDatabase(_client.get(), "test", "End of test"); + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("gmarks", "admin"))); ASSERT_TRUE(authzSession->mayBypassWriteBlockingMode()); @@ -1681,6 +1512,8 @@ TEST_F(AuthorizationSessionTest, MayBypassWriteBlockingModeIsSetCorrectly) { << "db" << "admin"))), BSONObj())); + authzSession->logoutDatabase(_client.get(), "admin", ""); + ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("admin", "admin"))); ASSERT_TRUE(authzSession->mayBypassWriteBlockingMode()); diff --git a/src/mongo/db/logical_session_id_test.cpp b/src/mongo/db/logical_session_id_test.cpp index 4585b419dd8..a54fc2316d7 100644 --- a/src/mongo/db/logical_session_id_test.cpp +++ b/src/mongo/db/logical_session_id_test.cpp @@ -272,20 +272,6 @@ TEST_F(LogicalSessionIdTest, GenWithUser) { ASSERT_EQ(lsid.getUid(), user->getDigest()); } -TEST_F(LogicalSessionIdTest, GenWithMultipleAuthedUsers) { - addSimpleUser(UserName("simple", "test")); - addSimpleUser(UserName("simple", "test2")); - - ASSERT_THROWS_WITH_CHECK(makeLogicalSessionId(_opCtx.get()), - AssertionException, - [](const AssertionException& exception) { - ASSERT_EQ(exception.code(), ErrorCodes::Unauthorized); - ASSERT_STRING_CONTAINS( - exception.reason(), - "docs.mongodb.com/manual/core/authentication"); - }); -} - TEST_F(LogicalSessionIdTest, GenWithoutAuthedUser) { ASSERT_THROWS(makeLogicalSessionId(_opCtx.get()), AssertionException); } @@ -461,22 +447,5 @@ TEST_F(LogicalSessionIdTest, ConstructorFromClientWithTooLongName) { ASSERT_THROWS(makeLogicalSessionId(req, _opCtx.get()), AssertionException); } -TEST_F(LogicalSessionIdTest, MultipleUsersPerSessionIsNotAllowed) { - addSimpleUser(UserName("simple", "test")); - addSimpleUser(UserName("simple", "test2")); - - LogicalSessionFromClient lsid; - lsid.setId(UUID::gen()); - - ASSERT_THROWS_CODE(initializeOperationSessionInfo( - _opCtx.get(), - BSON("TestCmd" << 1 << "lsid" << lsid.toBSON() << "txnNumber" << 100LL), - true, - true, - true), - AssertionException, - ErrorCodes::Unauthorized); -} - } // namespace } // namespace mongo diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js index 6379f2c81b3..b101d022f1e 100644 --- a/src/mongo/shell/replsettest.js +++ b/src/mongo/shell/replsettest.js @@ -187,7 +187,7 @@ var ReplSetTest = function(opts) { * assume that it already has the correct privileges. It is up to the caller of this function to * ensure that the connection is appropriately authenticated. */ - function asCluster(conn, fn, keyFileParam = self.keyFile) { + function asCluster(conn, fn, keyFileParam = undefined) { let connArray = conn; if (conn.length == null) connArray = [conn]; @@ -202,6 +202,7 @@ var ReplSetTest = function(opts) { const authMode = connOptions.clusterAuthMode || connArray[0].clusterAuthMode || jsTest.options().clusterAuthMode; + keyFileParam = keyFileParam || connOptions.keyFile || self.keyFile; let needsAuth = (keyFileParam || authMode === "x509" || authMode === "sendX509" || authMode === "sendKeyFile") && unauthenticatedConns.length > 0; @@ -356,6 +357,11 @@ var ReplSetTest = function(opts) { if (!conn) return false; + if (reconnectNode instanceof Function) { + // Allow caller to perform tasks on reconnect. + reconnectNode(conn); + } + asCluster(conn, function() { status = conn.getDB('admin').runCommand({replSetGetStatus: 1}); }); @@ -364,6 +370,11 @@ var ReplSetTest = function(opts) { return false; } + if (status.code == ErrorCodes.Unauthorized) { + // If we're not authorized already, then we never will be. + assert.commandWorked(status); // throws + } + var printStatus = false; if (lastTime == null || (currTime = new Date().getTime()) - (1000 * 5) > lastTime) { if (lastTime == null) { |