diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-05-18 17:34:06 -0400 |
---|---|---|
committer | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-09-27 22:51:17 -0400 |
commit | 2e98a18d2122a30549e089bf30b96ac0c3bbf85d (patch) | |
tree | 716ac83efa19cdc60810d1f200cc4047f3627547 | |
parent | 241515814f8bd5dbc7ad3a0682dd531a965537cb (diff) | |
download | mongo-2e98a18d2122a30549e089bf30b96ac0c3bbf85d.tar.gz |
SERVER-32064 Requests from the shell should use an implicit session by default
(cherry picked from commit 8817328f87564a29e9be2ed1a746cf40e89587eb)
SERVER-32064 Disable implicit sessions when checking db version during connect()
(cherry picked from commit 8c5002b06fd737f75941a73785ce75e3ca7f5ce1)
70 files changed, 612 insertions, 36 deletions
diff --git a/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml b/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml index a04502f765e..cbb4343774f 100644 --- a/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml +++ b/buildscripts/resmokeconfig/suites/causally_consistent_jscore_passthrough_auth.yml @@ -155,8 +155,21 @@ selector: - jstests/core/explain_upsert.js # The `dbstats` command builds in-memory structures that are not causally consistent. - jstests/core/dbstats.js + + # These include operations the root user auth'd on the test database is not authorized to perform, + # e.g. dropping or creating system collections. + - jstests/core/indexes_on_indexes.js + - jstests/core/list_collections_no_views.js + - jstests/core/rename8.js + - jstests/core/views/duplicate_ns.js + - jstests/core/views/invalid_system_views.js + - jstests/core/views/views_creation.js + - jstests/core/views/views_drop.js + - jstests/core/views/views_rename.js exclude_with_any_tags: - assumes_against_mongod_not_mongos + # TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + - creates_and_authenticates_user - requires_collstats ## # The next tag corresponds to the special error thrown by the set_read_preference_secondary.js @@ -167,6 +180,8 @@ selector: # "Cowardly refusing to run test with overridden read preference when it reads from a # non-replicated collection: ..." - assumes_read_preference_unchanged + # This suite runs as the root user, but eval requires universal privileges with authentication on. + - requires_eval_command executor: archive: @@ -190,7 +205,7 @@ executor: const res = db.runCommand({ createUser: username, pwd: password, - roles: ["dbOwner"], + roles: [{role: "root", db: jsTest.options().authenticationDatabase}] }); if (res.ok === 1) { @@ -201,7 +216,8 @@ executor: assert.commandFailedWithCode(res, ErrorCodes.DuplicateKey); } - db.logout(); + // Log out as the __system user and auth as the newly created user. + db.getSiblingDB(jsTest.options().authenticationDatabase).logout(); db.auth(username, password); })(); load("jstests/libs/override_methods/enable_causal_consistency.js"); diff --git a/buildscripts/resmokeconfig/suites/core_auth.yml b/buildscripts/resmokeconfig/suites/core_auth.yml index 198fb6d91a1..88845fcade2 100644 --- a/buildscripts/resmokeconfig/suites/core_auth.yml +++ b/buildscripts/resmokeconfig/suites/core_auth.yml @@ -18,6 +18,9 @@ selector: - jstests/core/**/*[aA]uth*.js # Commands using UUIDs are not compatible with name-based auth - jstests/core/commands_with_uuid.js + exclude_with_any_tags: + # TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + - creates_and_authenticates_user executor: archive: diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml index b92121d12eb..c5d6709947f 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_replication.yml @@ -13,6 +13,10 @@ executor: config: shell_options: readMode: commands + global_vars: + TestData: + # Other fuzzers test commands against replica sets with logical session ids. + disableImplicitSessions: true hooks: # The CheckReplDBHash hook waits until all operations have replicated to and have been applied # on the secondaries, so we run the ValidateCollections hook after it to ensure we're diff --git a/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml b/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml index 394b0af4ff6..65b093116eb 100644 --- a/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml +++ b/buildscripts/resmokeconfig/suites/jstestfuzz_sharded.yml @@ -11,6 +11,10 @@ executor: - ValidateCollections config: shell_options: + global_vars: + TestData: + # Other fuzzers test commands against sharded clusters with logical session ids. + disableImplicitSessions: true readMode: commands hooks: - class: CheckReplDBHash diff --git a/jstests/auth/auth1.js b/jstests/auth/auth1.js index 183317414df..6eff329e341 100644 --- a/jstests/auth/auth1.js +++ b/jstests/auth/auth1.js @@ -1,6 +1,9 @@ // test read/write permissions // skip this test on 32-bit platforms +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + function setupTest() { print("START auth1.js"); baseName = "jstests_auth_auth1"; diff --git a/jstests/auth/authentication_restrictions.js b/jstests/auth/authentication_restrictions.js index 17d656c9f05..d1fd44fe597 100644 --- a/jstests/auth/authentication_restrictions.js +++ b/jstests/auth/authentication_restrictions.js @@ -5,6 +5,9 @@ (function() { 'use strict'; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function testConnection( conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { load("jstests/libs/host_ipaddr.js"); diff --git a/jstests/auth/authentication_restrictions_role.js b/jstests/auth/authentication_restrictions_role.js index 80e9df6c794..759d874de3c 100644 --- a/jstests/auth/authentication_restrictions_role.js +++ b/jstests/auth/authentication_restrictions_role.js @@ -5,6 +5,9 @@ (function() { 'use strict'; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function testRestrictionCreationAndEnforcement( conn, eventuallyConsistentConn, sleepUntilUserDataPropagated, sleepUntilUserDataRefreshed) { load("jstests/libs/host_ipaddr.js"); diff --git a/jstests/auth/basic_role_auth.js b/jstests/auth/basic_role_auth.js index fc4e39089ba..c688f6e41b0 100644 --- a/jstests/auth/basic_role_auth.js +++ b/jstests/auth/basic_role_auth.js @@ -3,6 +3,12 @@ * environment. This file covers all types of operations except commands. */ +// This test runs connectionStatus on a connection with no logged in users and auth on, which is +// rejected when run with an implicit session id. +// TODO SERVER-34820: Remove once connectionStatus can be run with no users authenticated in an +// implicit session. +TestData.disableImplicitSessions = true; + /** * Data structure that contains all the users that are going to be used in the tests. * The structure is as follows: @@ -492,7 +498,7 @@ var runTests = function(conn) { testFunc.test(newConn); } catch (x) { failures.push(testFunc.name); - jsTestLog(x); + jsTestLog(tojson(x)); } }); diff --git a/jstests/auth/commands_builtin_roles.js b/jstests/auth/commands_builtin_roles.js index 14da86a505b..db3d3c3092d 100644 --- a/jstests/auth/commands_builtin_roles.js +++ b/jstests/auth/commands_builtin_roles.js @@ -7,6 +7,10 @@ in jstests/auth/commands.js. */ +// TODO SERVER-35447: This test involves killing all sessions, which will not work as expected if +// the kill command is sent with an implicit session. +TestData.disableImplicitSessions = true; + load("jstests/auth/lib/commands_lib.js"); var roles = [ diff --git a/jstests/auth/commands_user_defined_roles.js b/jstests/auth/commands_user_defined_roles.js index 3c8de27192f..765203fe1e4 100644 --- a/jstests/auth/commands_user_defined_roles.js +++ b/jstests/auth/commands_user_defined_roles.js @@ -7,6 +7,10 @@ in jstests/auth/commands.js. */ +// TODO SERVER-35447: This test involves killing all sessions, which will not work as expected if +// the kill command is sent with an implicit session. +TestData.disableImplicitSessions = true; + // constants var testUser = "userDefinedRolesTestUser"; var testRole = "userDefinedRolesTestRole"; diff --git a/jstests/auth/copyauth.js b/jstests/auth/copyauth.js index 0bad123cb98..6969600fcd2 100644 --- a/jstests/auth/copyauth.js +++ b/jstests/auth/copyauth.js @@ -194,6 +194,10 @@ function copydbBetweenClustersTest(configObj) { assert.eq(1, target.conn.getDB(baseName)[baseName].count()); assert.eq(1, target.conn.getDB(baseName)[baseName].findOne().i); + if (configObj.isTargetUsingAuth) { + target.conn.getDB("admin").logout(); + } + // 4. Do any necessary cleanup source.stop(); target.stop(); diff --git a/jstests/auth/getMore.js b/jstests/auth/getMore.js index 569376740fb..2caf8a03049 100644 --- a/jstests/auth/getMore.js +++ b/jstests/auth/getMore.js @@ -2,6 +2,9 @@ (function() { "use strict"; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function runTest(conn) { let adminDB = conn.getDB("admin"); let isMaster = adminDB.runCommand("ismaster"); diff --git a/jstests/auth/kill_cursors.js b/jstests/auth/kill_cursors.js index 146f3253282..4cbd5df0579 100644 --- a/jstests/auth/kill_cursors.js +++ b/jstests/auth/kill_cursors.js @@ -2,6 +2,9 @@ (function() { 'use strict'; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function runTest(mongod) { /** * Open a cursor on `db` while authenticated as `authUsers`. diff --git a/jstests/auth/kill_sessions.js b/jstests/auth/kill_sessions.js index b2090d28609..b07364bc0c2 100644 --- a/jstests/auth/kill_sessions.js +++ b/jstests/auth/kill_sessions.js @@ -3,6 +3,10 @@ load("jstests/libs/kill_sessions.js"); (function() { 'use strict'; + // TODO SERVER-35447: This test involves killing all sessions, which will not work as expected + // if the kill command is sent with an implicit session. + TestData.disableImplicitSessions = true; + var forExec = MongoRunner.runMongod({nojournal: "", auth: ""}); var forKill = new Mongo(forExec.host); var forVerify = new Mongo(forExec.host); diff --git a/jstests/auth/list_all_local_sessions.js b/jstests/auth/list_all_local_sessions.js index 05914b2c2e6..fdb40952393 100644 --- a/jstests/auth/list_all_local_sessions.js +++ b/jstests/auth/list_all_local_sessions.js @@ -4,6 +4,10 @@ 'use strict'; load('jstests/aggregation/extras/utils.js'); + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + function runListAllLocalSessionsTest(mongod) { assert(mongod); const admin = mongod.getDB("admin"); diff --git a/jstests/auth/list_all_sessions.js b/jstests/auth/list_all_sessions.js index 763178e9ac1..150ae957ba0 100644 --- a/jstests/auth/list_all_sessions.js +++ b/jstests/auth/list_all_sessions.js @@ -4,6 +4,10 @@ 'use strict'; load('jstests/aggregation/extras/utils.js'); + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + function runListAllSessionsTest(mongod) { assert(mongod); const admin = mongod.getDB("admin"); diff --git a/jstests/auth/list_local_sessions.js b/jstests/auth/list_local_sessions.js index 40cc66d991e..af4fce43aeb 100644 --- a/jstests/auth/list_local_sessions.js +++ b/jstests/auth/list_local_sessions.js @@ -4,6 +4,10 @@ 'use strict'; load('jstests/aggregation/extras/utils.js'); + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + function runListLocalSessionsTest(mongod) { assert(mongod); const admin = mongod.getDB('admin'); diff --git a/jstests/auth/list_sessions.js b/jstests/auth/list_sessions.js index b130999a3ef..2b12f77da91 100644 --- a/jstests/auth/list_sessions.js +++ b/jstests/auth/list_sessions.js @@ -4,6 +4,10 @@ 'use strict'; load('jstests/aggregation/extras/utils.js'); + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + function runListSessionsTest(mongod) { assert(mongod); const admin = mongod.getDB('admin'); diff --git a/jstests/auth/refresh_logical_session_cache_with_long_usernames.js b/jstests/auth/refresh_logical_session_cache_with_long_usernames.js index d9bbed5324f..e584a1b8345 100644 --- a/jstests/auth/refresh_logical_session_cache_with_long_usernames.js +++ b/jstests/auth/refresh_logical_session_cache_with_long_usernames.js @@ -4,6 +4,10 @@ (function() { 'use strict'; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + const mongod = MongoRunner.runMongod({auth: ""}); const refresh = {refreshLogicalSessionCacheNow: 1}; diff --git a/jstests/auth/rename.js b/jstests/auth/rename.js index c397ff1ad4b..0ae3eac3113 100644 --- a/jstests/auth/rename.js +++ b/jstests/auth/rename.js @@ -1,5 +1,8 @@ // test renameCollection with auth +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + var m = MongoRunner.runMongod({auth: ""}); var db1 = m.getDB("foo"); diff --git a/jstests/auth/repl_auth.js b/jstests/auth/repl_auth.js index aa851840bc5..a4958d5f101 100644 --- a/jstests/auth/repl_auth.js +++ b/jstests/auth/repl_auth.js @@ -64,4 +64,8 @@ for (var x = 0; x < 20; x++) { assert.eq(1, explain.executionStats.nReturned); } +admin.logout(); +fooDB0.logout(); +barDB1.logout(); + rsTest.stopSet(); diff --git a/jstests/auth/resource_pattern_matching.js b/jstests/auth/resource_pattern_matching.js index dd83b8bf273..d736a17b2aa 100644 --- a/jstests/auth/resource_pattern_matching.js +++ b/jstests/auth/resource_pattern_matching.js @@ -2,6 +2,11 @@ * Tests that resource pattern matching rules work as expected. */ +// TODO SERVER-35447: This test logs in users on the admin database, but doesn't log them out, which +// can fail with implicit sessions and ReplSetTest when the fixture attempts to verify data hashes +// at shutdown by authenticating as the __system user. +TestData.disableImplicitSessions = true; + function setup_users(granter) { var admindb = granter.getSiblingDB("admin"); admindb.runCommand({ diff --git a/jstests/auth/secondary_invalidation.js b/jstests/auth/secondary_invalidation.js index 3752a3aa678..fdd093e63ee 100644 --- a/jstests/auth/secondary_invalidation.js +++ b/jstests/auth/secondary_invalidation.js @@ -30,4 +30,7 @@ assert.doesNotThrow(function() { secondaryFoo.col.findOne(); }, [], "Secondary read did not work with permissions"); +admin.logout(); +secondaryFoo.logout(); + rsTest.stopSet(); diff --git a/jstests/auth/views_authz.js b/jstests/auth/views_authz.js index 4134a983ce9..dc1847d4873 100644 --- a/jstests/auth/views_authz.js +++ b/jstests/auth/views_authz.js @@ -5,6 +5,9 @@ (function() { "use strict"; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function runTest(conn) { // Create the admin user. let adminDB = conn.getDB("admin"); diff --git a/jstests/core/auth1.js b/jstests/core/auth1.js index 05450d14ddc..4f2a869ab44 100644 --- a/jstests/core/auth1.js +++ b/jstests/core/auth1.js @@ -1,4 +1,9 @@ -// @tags: [requires_non_retryable_commands, requires_auth, assumes_write_concern_unchanged] +// @tags: [ +// assumes_write_concern_unchanged, +// creates_and_authenticates_user, +// requires_auth, +// requires_non_retryable_commands, +// ] var mydb = db.getSiblingDB('auth1_db'); mydb.dropAllUsers(); diff --git a/jstests/core/connection_status.js b/jstests/core/connection_status.js index df1c59ab234..536443aaf9b 100644 --- a/jstests/core/connection_status.js +++ b/jstests/core/connection_status.js @@ -1,8 +1,9 @@ // @tags: [ -// requires_non_retryable_commands, -// requires_auth, -// assumes_write_concern_unchanged -// ] +// assumes_write_concern_unchanged, +// creates_and_authenticates_user, +// requires_auth, +// requires_non_retryable_commands, +// ] // Tests the connectionStatus command (function() { diff --git a/jstests/core/evalb.js b/jstests/core/evalb.js index d92573eef1c..96f2bbd7358 100644 --- a/jstests/core/evalb.js +++ b/jstests/core/evalb.js @@ -2,6 +2,8 @@ // contents are logged in the profile log. // // @tags: [ +// assumes_read_preference_unchanged, +// creates_and_authenticates_user, // does_not_support_stepdowns, // requires_eval_command, // requires_non_retryable_commands, diff --git a/jstests/core/mr_killop.js b/jstests/core/mr_killop.js index 25675fa64ab..b2afe735e01 100644 --- a/jstests/core/mr_killop.js +++ b/jstests/core/mr_killop.js @@ -18,6 +18,21 @@ function debug(x) { function op(childLoop) { p = db.currentOp().inprog; debug(p); + + let isMapReduce = function(op) { + if (!op.command) { + return false; + } + let cmdBody = op.command; + if (cmdBody.$truncated) { + let stringifiedCmd = cmdBody.$truncated; + print('str: ' + tojson(stringifiedCmd)); + return stringifiedCmd.search('mapreduce') >= 0 && + stringifiedCmd.search('jstests_mr_killop') >= 0; + } + return cmdBody.mapreduce && cmdBody.mapreduce == "jstests_mr_killop"; + }; + for (var i in p) { var o = p[i]; // Identify a map/reduce or where distinct operation by its collection, whether or not @@ -28,8 +43,7 @@ function op(childLoop) { return o.opid; } } else { - if ((o.active || o.waitingForLock) && o.command && o.command.mapreduce && - o.command.mapreduce == "jstests_mr_killop") { + if ((o.active || o.waitingForLock) && isMapReduce(o)) { return o.opid; } } diff --git a/jstests/core/profile1.js b/jstests/core/profile1.js index 4109c3ac55d..730bb91a33a 100644 --- a/jstests/core/profile1.js +++ b/jstests/core/profile1.js @@ -1,4 +1,9 @@ -// @tags: [does_not_support_stepdowns, requires_non_retryable_commands, requires_collstats] +// @tags: [ +// creates_and_authenticates_user, +// does_not_support_stepdowns, +// requires_collstats, +// requires_non_retryable_commands, +// ] (function() { "use strict"; diff --git a/jstests/core/profile3.js b/jstests/core/profile3.js index 3a22bd1f952..02c6d272f8e 100644 --- a/jstests/core/profile3.js +++ b/jstests/core/profile3.js @@ -1,4 +1,4 @@ - +// @tags: [creates_and_authenticates_user] // special db so that it can be run in parallel tests var stddb = db; var db = db.getSisterDB("profile3"); diff --git a/jstests/core/user_management_helpers.js b/jstests/core/user_management_helpers.js index 2b5abe9a388..65d5a37cd43 100644 --- a/jstests/core/user_management_helpers.js +++ b/jstests/core/user_management_helpers.js @@ -1,8 +1,9 @@ // @tags: [ -// requires_non_retryable_commands, -// requires_auth, -// assumes_write_concern_unchanged -// ] +// assumes_write_concern_unchanged, +// creates_and_authenticates_user, +// requires_auth, +// requires_non_retryable_commands, +// ] // 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 diff --git a/jstests/multiVersion/mixed_storage_version_replication.js b/jstests/multiVersion/mixed_storage_version_replication.js index da0a4309bcc..a62f66a3bb6 100644 --- a/jstests/multiVersion/mixed_storage_version_replication.js +++ b/jstests/multiVersion/mixed_storage_version_replication.js @@ -4,6 +4,11 @@ * storage engines, do a bunch of random work, and assert that it replicates the same way on all * nodes. */ + +// This test randomly generates operations, which may include direct writes against +// config.transactions, which are not allowed to run under a session. +TestData.disableImplicitSessions = true; + load('jstests/libs/parallelTester.js'); load("jstests/replsets/rslib.js"); @@ -567,6 +572,10 @@ function assertSameData(primary, conns) { * function to pass to a thread to make it start doing random commands/CRUD operations. */ function startCmds(randomOps, host) { + // This test randomly generates operations, which may include direct writes against + // config.transactions, which are not allowed to run under a session. + TestData = {disableImplicitSessions: true}; + var ops = [ "insert", "remove", @@ -593,6 +602,10 @@ function startCmds(randomOps, host) { * function to pass to a thread to make it start doing random CRUD operations. */ function startCRUD(randomOps, host) { + // This test randomly generates operations, which may include direct writes against + // config.transactions, which are not allowed to run under a session. + TestData = {disableImplicitSessions: true}; + var m = new Mongo(host); var numOps = 500; Random.setRandomSeed(); diff --git a/jstests/noPassthrough/aggregation_cursor_invalidations.js b/jstests/noPassthrough/aggregation_cursor_invalidations.js index 887f97b567d..6c4e6ba4a54 100644 --- a/jstests/noPassthrough/aggregation_cursor_invalidations.js +++ b/jstests/noPassthrough/aggregation_cursor_invalidations.js @@ -12,6 +12,10 @@ (function() { 'use strict'; + // This test runs a getMore in a parallel shell, which will not inherit the implicit session of + // the cursor establishing command. + TestData.disableImplicitSessions = true; + // The DocumentSourceCursor which wraps PlanExecutors will batch results internally. We use the // 'internalDocumentSourceCursorBatchSizeBytes' parameter to disable this behavior so that we // can easily pause a pipeline in a state where it will need to request more results from the diff --git a/jstests/noPassthrough/count_helper_read_preference.js b/jstests/noPassthrough/count_helper_read_preference.js index 63b5faed2ce..619773c3563 100644 --- a/jstests/noPassthrough/count_helper_read_preference.js +++ b/jstests/noPassthrough/count_helper_read_preference.js @@ -19,7 +19,12 @@ commandsRan.push({db: db, cmd: cmd, opts: opts}); return {ok: 1, n: 100}; }; - var db = new DB(new MockMongo(), "test"); + + const mockMongo = new MockMongo(); + var db = new DB(mockMongo, "test"); + + // Attach a dummy implicit session because the mock connection cannot create sessions. + db._session = new _DummyDriverSession(mockMongo); assert.eq(commandsRan.length, 0); diff --git a/jstests/noPassthrough/currentop_includes_await_time.js b/jstests/noPassthrough/currentop_includes_await_time.js index 0c34999a512..a8ec126f6d7 100644 --- a/jstests/noPassthrough/currentop_includes_await_time.js +++ b/jstests/noPassthrough/currentop_includes_await_time.js @@ -5,6 +5,10 @@ (function() { "use test"; + // This test runs a getMore in a parallel shell, which will not inherit the implicit session of + // the cursor establishing command. + TestData.disableImplicitSessions = true; + const conn = MongoRunner.runMongod({}); assert.neq(null, conn, "mongod was unable to start up"); const testDB = conn.getDB("test"); diff --git a/jstests/noPassthrough/currentop_query.js b/jstests/noPassthrough/currentop_query.js index 3dbde751fe4..ff276cc3af6 100644 --- a/jstests/noPassthrough/currentop_query.js +++ b/jstests/noPassthrough/currentop_query.js @@ -5,6 +5,10 @@ (function() { "use strict"; + // This test runs manual getMores using different connections, which will not inherit the + // implicit session of the cursor establishing command. + TestData.disableImplicitSessions = true; + /** * @param {string} readMode - The read mode to use for the parallel shell. This allows * testing currentOp() output for both OP_QUERY and OP_GET_MORE queries, as well as "find" and diff --git a/jstests/noPassthrough/end_sessions_command.js b/jstests/noPassthrough/end_sessions_command.js index 07bc9316494..863d14f51ff 100644 --- a/jstests/noPassthrough/end_sessions_command.js +++ b/jstests/noPassthrough/end_sessions_command.js @@ -1,6 +1,10 @@ (function() { "use script"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var res; var refresh = {refreshLogicalSessionCacheNow: 1}; var startSession = {startSession: 1}; diff --git a/jstests/noPassthrough/implicit_sessions.js b/jstests/noPassthrough/implicit_sessions.js new file mode 100644 index 00000000000..350571164b9 --- /dev/null +++ b/jstests/noPassthrough/implicit_sessions.js @@ -0,0 +1,265 @@ +/** + * Verifies behavior around implicit sessions in the mongo shell. + */ +(function() { + "use strict"; + + /** + * Runs the given function, inspecting the outgoing command object and making assertions about + * its logical session id. + */ + function inspectCommandForSessionId(func, {shouldIncludeId, expectedId, differentFromId}) { + const mongoRunCommandOriginal = Mongo.prototype.runCommand; + + const sentinel = {}; + let cmdObjSeen = sentinel; + + Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) { + cmdObjSeen = cmdObj; + return mongoRunCommandOriginal.apply(this, arguments); + }; + + try { + assert.doesNotThrow(func); + } finally { + Mongo.prototype.runCommand = mongoRunCommandOriginal; + } + + if (cmdObjSeen === sentinel) { + throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString()); + } + + // If the command is in a wrapped form, then we look for the actual command object inside + // the query/$query object. + let cmdName = Object.keys(cmdObjSeen)[0]; + if (cmdName === "query" || cmdName === "$query") { + cmdObjSeen = cmdObjSeen[cmdName]; + cmdName = Object.keys(cmdObjSeen)[0]; + } + + if (shouldIncludeId) { + assert(cmdObjSeen.hasOwnProperty("lsid"), + "Expected operation " + tojson(cmdObjSeen) + " to have a logical session id."); + + if (expectedId) { + assert(bsonBinaryEqual(expectedId, cmdObjSeen.lsid), + "The sent session id did not match the expected, sent: " + + tojson(cmdObjSeen.lsid) + ", expected: " + tojson(expectedId)); + } + + if (differentFromId) { + assert(!bsonBinaryEqual(differentFromId, cmdObjSeen.lsid), + "The sent session id was not different from the expected, sent: " + + tojson(cmdObjSeen.lsid) + ", expected: " + tojson(differentFromId)); + } + + } else { + assert( + !cmdObjSeen.hasOwnProperty("lsid"), + "Expected operation " + tojson(cmdObjSeen) + " to not have a logical session id."); + } + + return cmdObjSeen.lsid; + } + + // Tests regular behavior of implicit sessions. + function runTest() { + const conn = MongoRunner.runMongod(); + + // Commands run on a database without an explicit session should use an implicit one. + const testDB = conn.getDB("test"); + const coll = testDB.getCollection("foo"); + const implicitId = inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true}); + + assert(bsonBinaryEqual(testDB.getSession().getSessionId(), implicitId), + "Expected the id of the database's implicit session to match the one sent, sent: " + + tojson(implicitId) + " db session id: " + + tojson(testDB.getSession().getSessionId())); + + // Implicit sessions are not causally consistent. + assert(!testDB.getSession().getOptions().isCausalConsistency(), + "Expected the database's implicit session to not be causally consistent"); + + // Further commands run on the same database should reuse the implicit session. + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // New collections from the same database should inherit the implicit session. + const collTwo = testDB.getCollection("bar"); + inspectCommandForSessionId(function() { + assert.writeOK(collTwo.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // Sibling databases should inherit the implicit session. + let siblingColl = testDB.getSiblingDB("foo").getCollection("bar"); + inspectCommandForSessionId(function() { + assert.writeOK(siblingColl.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // A new database from the same connection should inherit the implicit session. + const newCollSameConn = conn.getDB("testTwo").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(newCollSameConn.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // A new database from a new connection should use a different implicit session. + const newCollNewConn = new Mongo(conn.host).getDB("test").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(newCollNewConn.insert({x: 1})); + }, {shouldIncludeId: true, differentFromId: implicitId}); + + // The original implicit session should still live on the first database. + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // Databases created from an explicit session should override any implicit sessions. + const session = conn.startSession(); + const sessionColl = session.getDatabase("test").getCollection("foo"); + const explicitId = inspectCommandForSessionId(function() { + assert.writeOK(sessionColl.insert({x: 1})); + }, {shouldIncludeId: true, differentFromId: implicitId}); + + assert(bsonBinaryEqual(session.getSessionId(), explicitId), + "Expected the id of the explicit session to match the one sent, sent: " + + tojson(explicitId) + " explicit session id: " + tojson(session.getSessionId())); + assert(bsonBinaryEqual(sessionColl.getDB().getSession().getSessionId(), explicitId), + "Expected id of the database's session to match the explicit session's id, sent: " + + tojson(sessionColl.getDB().getSession().getSessionId()) + + ", explicit session id: " + tojson(session.getSessionId())); + + // The original implicit session should still live on the first database. + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + // New databases on the same connection as the explicit session should still inherit the + // original implicit session. + const newCollSameConnAfter = conn.getDB("testThree").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(newCollSameConnAfter.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + session.endSession(); + MongoRunner.stopMongod(conn); + } + + // Tests behavior when the test flag to disable implicit sessions is changed. + function runTestTransitionToDisabled() { + const conn = MongoRunner.runMongod(); + + // Existing implicit sessions should be erased when the disable flag is set. + const coll = conn.getDB("test").getCollection("foo"); + const implicitId = inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true}); + + TestData.disableImplicitSessions = true; + + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: false}); + + // After the flag is unset, databases using existing connections with implicit sessions will + // use the original implicit sessions again and new connections will create and use new + // implicit sessions. + TestData.disableImplicitSessions = false; + + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + const newColl = conn.getDB("test").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(newColl.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: implicitId}); + + const newCollNewConn = new Mongo(conn.host).getDB("test").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(newCollNewConn.insert({x: 1})); + }, {shouldIncludeId: true, differentFromId: implicitId}); + + // Explicit sessions should not be affected by the disable flag being set. + const session = conn.startSession(); + const sessionColl = session.getDatabase("test").getCollection("foo"); + const explicitId = inspectCommandForSessionId(function() { + assert.writeOK(sessionColl.insert({x: 1})); + }, {shouldIncludeId: true}); + + TestData.disableImplicitSessions = true; + + inspectCommandForSessionId(function() { + assert.writeOK(sessionColl.insert({x: 1})); + }, {shouldIncludeId: true, expectedId: explicitId}); + + session.endSession(); + MongoRunner.stopMongod(conn); + } + + // Tests for the shell parameter, and the function that exposes it, for disabling implicit + // sessions. + function runTestGlobalFlag() { + const conn = MongoRunner.runMongod(); + const testDB = conn.getDB("test"); + + // The native disabled function should return false in the mongo shell by default. + assert(_shouldUseImplicitSessions()); + + // Commands run in eval should never use implicit sessions. + const evalFunc = function() { + assert(!_shouldUseImplicitSessions(), + "expected implicit sessions to be disabled inside eval"); + + inspectCommandForSessionId(function() { + assert.writeOK(db.foo.insert({x: 1})); + }, {shouldIncludeId: false}); + }; + testDB.eval("inspectCommandForSessionId = " + inspectCommandForSessionId.toString() + + "; (" + evalFunc.toString() + ")()"); + + MongoRunner.stopMongod(conn); + } + + // Tests behavior of implicit sessions when they are disabled via a test flag. + function runTestDisabled() { + const conn = MongoRunner.runMongod(); + + // Commands run without an explicit session should not use an implicit one. + const coll = conn.getDB("test").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(coll.insert({x: 1})); + }, {shouldIncludeId: false}); + + // Explicit sessions should still include session ids. + const session = conn.startSession(); + const sessionColl = session.getDatabase("test").getCollection("foo"); + inspectCommandForSessionId(function() { + assert.writeOK(sessionColl.insert({x: 1})); + }, {shouldIncludeId: true}); + + // Commands run in a parallel shell inherit the disable flag. + TestData.inspectCommandForSessionId = inspectCommandForSessionId; + const awaitShell = startParallelShell(function() { + const parallelColl = db.getCollection("foo"); + TestData.inspectCommandForSessionId(function() { + assert.writeOK(parallelColl.insert({x: 1})); + }, {shouldIncludeId: false}); + }, conn.port); + awaitShell(); + + session.endSession(); + MongoRunner.stopMongod(conn); + } + + runTest(); + + runTestTransitionToDisabled(); + + runTestGlobalFlag(); + + TestData.disableImplicitSessions = true; + runTestDisabled(); +})(); diff --git a/jstests/noPassthrough/kill_sessions.js b/jstests/noPassthrough/kill_sessions.js index bd804fa4528..16cb100d31e 100644 --- a/jstests/noPassthrough/kill_sessions.js +++ b/jstests/noPassthrough/kill_sessions.js @@ -3,6 +3,10 @@ load("jstests/libs/kill_sessions.js"); (function() { 'use strict'; + // TODO SERVER-35447: This test involves killing all sessions, which will not work as expected + // if the kill command is sent with an implicit session. + TestData.disableImplicitSessions = true; + var conn = MongoRunner.runMongod({nojournal: ""}); KillSessionsTestHelper.runNoAuth(conn, conn, [conn]); MongoRunner.stopMongod(conn); diff --git a/jstests/noPassthrough/refresh_logical_session_cache_now.js b/jstests/noPassthrough/refresh_logical_session_cache_now.js index 294a16043d2..59d181845fe 100644 --- a/jstests/noPassthrough/refresh_logical_session_cache_now.js +++ b/jstests/noPassthrough/refresh_logical_session_cache_now.js @@ -1,6 +1,10 @@ (function() { "use script"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var res; var refresh = {refreshLogicalSessionCacheNow: 1}; var startSession = {startSession: 1}; diff --git a/jstests/noPassthrough/refresh_sessions_command.js b/jstests/noPassthrough/refresh_sessions_command.js index 2348b8cf2a4..d601c06aea0 100644 --- a/jstests/noPassthrough/refresh_sessions_command.js +++ b/jstests/noPassthrough/refresh_sessions_command.js @@ -1,6 +1,10 @@ (function() { "use strict"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var conn; var admin; var result; diff --git a/jstests/noPassthrough/sessions_collection_auto_healing.js b/jstests/noPassthrough/sessions_collection_auto_healing.js index 58c64561161..21eb3d221a3 100644 --- a/jstests/noPassthrough/sessions_collection_auto_healing.js +++ b/jstests/noPassthrough/sessions_collection_auto_healing.js @@ -3,6 +3,10 @@ load('jstests/libs/sessions_collection.js'); (function() { "use strict"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var startSession = {startSession: 1}; var conn = MongoRunner.runMongod({nojournal: ""}); diff --git a/jstests/noPassthrough/shell_can_use_read_concern.js b/jstests/noPassthrough/shell_can_use_read_concern.js index 74e7ff3ad8a..3e3bd3b7b1e 100644 --- a/jstests/noPassthrough/shell_can_use_read_concern.js +++ b/jstests/noPassthrough/shell_can_use_read_concern.js @@ -5,6 +5,9 @@ (function() { "use strict"; + // This test makes assertions on commands run without logical session ids. + TestData.disableImplicitSessions = true; + const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); diff --git a/jstests/noPassthrough/start_session_command.js b/jstests/noPassthrough/start_session_command.js index a22016053b9..b13b63fb3fb 100644 --- a/jstests/noPassthrough/start_session_command.js +++ b/jstests/noPassthrough/start_session_command.js @@ -1,5 +1,10 @@ (function() { 'use strict'; + + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var conn; var admin; var foo; diff --git a/jstests/noPassthrough/transaction_reaper.js b/jstests/noPassthrough/transaction_reaper.js index 5cce0d17f2f..c4ef142dc27 100644 --- a/jstests/noPassthrough/transaction_reaper.js +++ b/jstests/noPassthrough/transaction_reaper.js @@ -1,6 +1,10 @@ (function() { 'use strict'; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + load("jstests/libs/retryable_writes_util.js"); if (!RetryableWritesUtil.storageEngineSupportsRetryableWrites(jsTest.options().storageEngine)) { diff --git a/jstests/noPassthrough/verify_session_cache_updates.js b/jstests/noPassthrough/verify_session_cache_updates.js index e2d51bd27e5..d57b35a4d28 100644 --- a/jstests/noPassthrough/verify_session_cache_updates.js +++ b/jstests/noPassthrough/verify_session_cache_updates.js @@ -1,6 +1,10 @@ (function() { 'use strict'; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + function runTest(conn) { for (var i = 0; i < 10; ++i) { conn.getDB("test").test.save({a: i}); diff --git a/jstests/replsets/auth1.js b/jstests/replsets/auth1.js index 211beb9016e..ddf0fb9b193 100644 --- a/jstests/replsets/auth1.js +++ b/jstests/replsets/auth1.js @@ -6,6 +6,11 @@ load("jstests/replsets/rslib.js"); (function() { + "use strict"; + + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + var name = "rs_auth1"; var port = allocatePorts(5); var path = "jstests/libs/"; diff --git a/jstests/replsets/refresh_sessions_rs.js b/jstests/replsets/refresh_sessions_rs.js index 338db1bd817..caae49a5801 100644 --- a/jstests/replsets/refresh_sessions_rs.js +++ b/jstests/replsets/refresh_sessions_rs.js @@ -1,6 +1,9 @@ (function() { "use strict"; + // This test makes assertions about the number of logical session records. + TestData.disableImplicitSessions = true; + var refresh = {refreshLogicalSessionCacheNow: 1}; var startSession = {startSession: 1}; diff --git a/jstests/replsets/retryable_writes_direct_write_to_config_transactions.js b/jstests/replsets/retryable_writes_direct_write_to_config_transactions.js index 4326437b50b..1fcc8b809b5 100644 --- a/jstests/replsets/retryable_writes_direct_write_to_config_transactions.js +++ b/jstests/replsets/retryable_writes_direct_write_to_config_transactions.js @@ -2,6 +2,9 @@ (function() { 'use strict'; + // Direct writes to config.transactions cannot be part of a session. + TestData.disableImplicitSessions = true; + load("jstests/libs/retryable_writes_util.js"); if (!RetryableWritesUtil.storageEngineSupportsRetryableWrites(jsTest.options().storageEngine)) { diff --git a/jstests/replsets/rollback_auth.js b/jstests/replsets/rollback_auth.js index b30f9833131..1b6916e6d4a 100644 --- a/jstests/replsets/rollback_auth.js +++ b/jstests/replsets/rollback_auth.js @@ -12,6 +12,10 @@ (function() { "use strict"; + + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + // helper function for verifying contents at the end of the test var checkFinalResults = function(db) { assert.commandWorked(db.runCommand({dbStats: 1})); diff --git a/jstests/replsets/rollback_transaction_table.js b/jstests/replsets/rollback_transaction_table.js index 6c32be314e8..cd740e41a4b 100644 --- a/jstests/replsets/rollback_transaction_table.js +++ b/jstests/replsets/rollback_transaction_table.js @@ -20,6 +20,10 @@ (function() { "use strict"; + // This test drops a collection in the config database, which is not allowed under a session. It + // also manually simulates a session, which is not compatible with implicit sessions. + TestData.disableImplicitSessions = true; + load("jstests/libs/retryable_writes_util.js"); if (!RetryableWritesUtil.storageEngineSupportsRetryableWrites(jsTest.options().storageEngine)) { diff --git a/jstests/replsets/sessions_collection_auto_healing.js b/jstests/replsets/sessions_collection_auto_healing.js index 0b7cd9ef612..c56fb24639a 100644 --- a/jstests/replsets/sessions_collection_auto_healing.js +++ b/jstests/replsets/sessions_collection_auto_healing.js @@ -3,6 +3,10 @@ load('jstests/libs/sessions_collection.js'); (function() { "use strict"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var replTest = new ReplSetTest({ name: 'refresh', nodes: [{rsConfig: {votes: 1, priority: 1}}, {rsConfig: {votes: 0, priority: 0}}] diff --git a/jstests/replsets/user_management_wc.js b/jstests/replsets/user_management_wc.js index c8ac612b597..8eba68a4075 100644 --- a/jstests/replsets/user_management_wc.js +++ b/jstests/replsets/user_management_wc.js @@ -10,6 +10,10 @@ load('jstests/multiVersion/libs/auth_helpers.js'); (function() { "use strict"; + + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + var replTest = new ReplSetTest( {name: 'UserManagementWCSet', nodes: 3, settings: {chainingAllowed: false}}); replTest.startSet(); diff --git a/jstests/sharding/advance_cluster_time_action_type.js b/jstests/sharding/advance_cluster_time_action_type.js index d01357ec338..87679080b2d 100644 --- a/jstests/sharding/advance_cluster_time_action_type.js +++ b/jstests/sharding/advance_cluster_time_action_type.js @@ -5,8 +5,12 @@ (function() { "use strict"; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + let st = new ShardingTest( {mongos: 1, config: 1, shards: 1, keyFile: 'jstests/libs/key1', mongosWaitsForKeys: true}); + let adminDB = st.s.getDB('admin'); assert.commandWorked(adminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]})); diff --git a/jstests/sharding/authCommands.js b/jstests/sharding/authCommands.js index 497a5748466..1ff86edb039 100644 --- a/jstests/sharding/authCommands.js +++ b/jstests/sharding/authCommands.js @@ -4,6 +4,9 @@ (function() { 'use strict'; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + load("jstests/replsets/rslib.js"); var st = new ShardingTest({ diff --git a/jstests/sharding/auth_repl.js b/jstests/sharding/auth_repl.js index 9e1ddb06873..0c8e976bd48 100644 --- a/jstests/sharding/auth_repl.js +++ b/jstests/sharding/auth_repl.js @@ -1,3 +1,6 @@ +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + var replTest = new ReplSetTest({nodes: 3, useHostName: false, keyFile: 'jstests/libs/key1'}); replTest.startSet({oplogSize: 10}); replTest.initiate(); diff --git a/jstests/sharding/cleanup_orphaned_auth.js b/jstests/sharding/cleanup_orphaned_auth.js index 834ad613a38..941dafcd44d 100644 --- a/jstests/sharding/cleanup_orphaned_auth.js +++ b/jstests/sharding/cleanup_orphaned_auth.js @@ -5,6 +5,9 @@ (function() { 'use strict'; + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function assertUnauthorized(res, msg) { if (assert._debug && msg) print("in assert for: " + msg); diff --git a/jstests/sharding/commands_that_write_accept_wc_configRS.js b/jstests/sharding/commands_that_write_accept_wc_configRS.js index 06326fa7403..ea864435604 100644 --- a/jstests/sharding/commands_that_write_accept_wc_configRS.js +++ b/jstests/sharding/commands_that_write_accept_wc_configRS.js @@ -17,6 +17,10 @@ load('jstests/multiVersion/libs/auth_helpers.js'); (function() { "use strict"; + + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + var st = new ShardingTest({ shards: { rs0: {nodes: 3, settings: {chainingAllowed: false}}, diff --git a/jstests/sharding/kill_sessions.js b/jstests/sharding/kill_sessions.js index 2757ef8935d..2af0a6a0658 100644 --- a/jstests/sharding/kill_sessions.js +++ b/jstests/sharding/kill_sessions.js @@ -3,6 +3,10 @@ load("jstests/libs/kill_sessions.js"); (function() { 'use strict'; + // TODO SERVER-35447: This test involves killing all sessions, which will not work as expected + // if the kill command is sent with an implicit session. + TestData.disableImplicitSessions = true; + function runTests(needAuth) { var other = { rs: true, diff --git a/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js b/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js index 3c9cf3e6af7..eab329791dd 100644 --- a/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js +++ b/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js @@ -8,6 +8,10 @@ (function() { "use strict"; + // This test uses authentication and runs commands without authenticating, which is not + // compatible with implicit sessions. + TestData.disableImplicitSessions = true; + load("jstests/multiVersion/libs/multi_rs.js"); // TODO SERVER-32672: remove this flag. @@ -48,6 +52,7 @@ priRSConn.auth(rUser.username, rUser.password); const resWithKeys = priRSConn.runCommand({isMaster: 1}); assertContainsValidLogicalTime(resWithKeys); + priRSConn.logout(); // Enable the failpoint, remove all keys, and restart the config servers with the failpoint // still enabled to guarantee there are no keys. @@ -62,6 +67,7 @@ }); assert(adminDB.system.keys.count() == 0, "expected there to be no keys on the config server"); + adminDB.logout(); st.configRS.stopSet(null /* signal */, true /* forRestart */); st.configRS.startSet( @@ -74,6 +80,7 @@ priRSConn.auth(rUser.username, rUser.password); const resNoKeys = priRSConn.runCommand({isMaster: 1}); assert.commandWorked(resNoKeys); + priRSConn.logout(); assert.eq(resNoKeys.hasOwnProperty("$clusterTime"), false); assert.eq(resNoKeys.hasOwnProperty("operationTime"), false); diff --git a/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js b/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js index a5ae6c62aa6..b8e4e02a279 100644 --- a/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js +++ b/jstests/sharding/mongos_rs_auth_shard_failure_tolerance.js @@ -15,6 +15,9 @@ // shard does not have a primary. TestData.skipCheckingUUIDsConsistentAcrossCluster = true; +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + var options = {rs: true, rsOptions: {nodes: 2}, keyFile: "jstests/libs/key1"}; var st = new ShardingTest({shards: 3, mongos: 1, other: options}); diff --git a/jstests/sharding/mrShardedOutputAuth.js b/jstests/sharding/mrShardedOutputAuth.js index 93164e5e128..63b36a39f4d 100644 --- a/jstests/sharding/mrShardedOutputAuth.js +++ b/jstests/sharding/mrShardedOutputAuth.js @@ -6,6 +6,9 @@ (function() { + // TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. + TestData.disableImplicitSessions = true; + function doMapReduce(connection, outputDb) { // clean output db and run m/r outputDb.numbers_out.drop(); diff --git a/jstests/sharding/refresh_sessions.js b/jstests/sharding/refresh_sessions.js index 8199ffb4563..ee4ee125db3 100644 --- a/jstests/sharding/refresh_sessions.js +++ b/jstests/sharding/refresh_sessions.js @@ -1,6 +1,9 @@ (function() { "use strict"; + // This test makes assumptions about the number of logical sessions. + TestData.disableImplicitSessions = true; + var sessionsDb = "config"; var refresh = {refreshLogicalSessionCacheNow: 1}; var startSession = {startSession: 1}; diff --git a/jstests/sharding/sessions_collection_auto_healing.js b/jstests/sharding/sessions_collection_auto_healing.js index 5dcf6d66590..61271bd8dc5 100644 --- a/jstests/sharding/sessions_collection_auto_healing.js +++ b/jstests/sharding/sessions_collection_auto_healing.js @@ -3,6 +3,10 @@ load('jstests/libs/sessions_collection.js'); (function() { "use strict"; + // This test makes assertions about the number of sessions, which are not compatible with + // implicit sessions. + TestData.disableImplicitSessions = true; + var st = new ShardingTest({shards: 0}); var configSvr = st.configRS.getPrimary(); var configAdmin = configSvr.getDB("admin"); diff --git a/jstests/sharding/sharding_options.js b/jstests/sharding/sharding_options.js index 8af7bf01c53..190d78a1e94 100644 --- a/jstests/sharding/sharding_options.js +++ b/jstests/sharding/sharding_options.js @@ -1,3 +1,6 @@ +// TODO SERVER-35447: Multiple users cannot be authenticated on one connection within a session. +TestData.disableImplicitSessions = true; + var baseName = "jstests_sharding_sharding_options"; load('jstests/libs/command_line/test_parsed_options.js'); diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js index a7c6bf82b76..faf2b624b66 100644 --- a/src/mongo/shell/mongo.js +++ b/src/mongo/shell/mongo.js @@ -58,7 +58,9 @@ Mongo.prototype.getDB = function(name) { Mongo.prototype.getDBs = function(driverSession = this._getDefaultSession()) { var cmdObj = {listDatabases: 1}; - cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + if (driverSession._isExplicit || !jsTest.options().disableImplicitSessions) { + cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + } var res = this.adminCommand(cmdObj); if (!res.ok) @@ -75,7 +77,9 @@ Mongo.prototype.adminCommand = function(cmd) { */ Mongo.prototype.getLogComponents = function(driverSession = this._getDefaultSession()) { var cmdObj = {getParameter: 1, logComponentVerbosity: 1}; - cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + if (driverSession._isExplicit || !jsTest.options().disableImplicitSessions) { + cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + } var res = this.adminCommand(cmdObj); if (!res.ok) @@ -106,7 +110,9 @@ Mongo.prototype.setLogLevel = function( } var cmdObj = {setParameter: 1, logComponentVerbosity: vDoc}; - cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + if (driverSession._isExplicit || !jsTest.options().disableImplicitSessions) { + cmdObj = driverSession._serverSession.injectSessionId(cmdObj); + } var res = this.adminCommand(cmdObj); if (!res.ok) @@ -257,13 +263,22 @@ connect = function(url, user, pass) { } } - // Check server version - var serverVersion = db.version(); - chatty("MongoDB server version: " + serverVersion); - - var shellVersion = version(); - if (serverVersion.slice(0, 3) != shellVersion.slice(0, 3)) { - chatty("WARNING: shell and server versions do not match"); + // Implicit sessions should not be used when opening a connection. In particular, the buildInfo + // command is erroneously marked as requiring auth in MongoDB 3.6 and therefore fails if a + // logical session id is included in the request. + const originalTestData = TestData; + TestData = Object.merge(originalTestData, {disableImplicitSessions: true}); + try { + // Check server version + var serverVersion = db.version(); + chatty("MongoDB server version: " + serverVersion); + + var shellVersion = version(); + if (serverVersion.slice(0, 3) != shellVersion.slice(0, 3)) { + chatty("WARNING: shell and server versions do not match"); + } + } finally { + TestData = originalTestData; } return db; @@ -426,11 +441,14 @@ Mongo.prototype.startSession = function startSession(options = {}) { }; Mongo.prototype._getDefaultSession = function getDefaultSession() { - // We implicitly associate a Mongo connection object with a DriverSession so that tests which - // call DB.prototype.getMongo() and then Mongo.prototype.getDB() to get a different DB instance - // are still causally consistent. + // We implicitly associate a Mongo connection object with a real session so all requests include + // a logical session id. These implicit sessions are intentionally not causally consistent. If + // implicit sessions have been globally disabled, a dummy session is used instead of a real one. if (!this.hasOwnProperty("_defaultSession")) { - this._defaultSession = new _DummyDriverSession(this); + this._defaultSession = _shouldUseImplicitSessions() + ? this.startSession({causalConsistency: false}) + : new _DummyDriverSession(this); + this._defaultSession._isExplicit = false; } return this._defaultSession; }; diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js index 479668e41c4..864ef774e3a 100644 --- a/src/mongo/shell/query.js +++ b/src/mongo/shell/query.js @@ -116,10 +116,11 @@ DBQuery.prototype._exec = function() { var cmdRes = this._db.runReadCommand(findCmd, null, this._options); this._cursor = new DBCommandCursor(this._db, cmdRes, this._batchSize); } else { - // Note that depending on how SERVER-32064 is implemented, we may need to alter this - // check to account for implicit sessions, so that exhaust cursors can still be used in - // the shell. - if (this._db.getSession().getSessionId() !== null) { + // The exhaust cursor option is disallowed under a session because it doesn't work as + // expected, but all requests from the shell use implicit sessions, so to allow users + // to continue using exhaust cursors through the shell, they are only disallowed with + // explicit sessions. + if (this._db.getSession()._isExplicit) { throw new Error("Cannot run a legacy query on a session."); } diff --git a/src/mongo/shell/session.js b/src/mongo/shell/session.js index c3d790346f5..ecd80b288cb 100644 --- a/src/mongo/shell/session.js +++ b/src/mongo/shell/session.js @@ -199,7 +199,14 @@ var { } function prepareCommandRequest(driverSession, cmdObj) { - if (serverSupports(kWireVersionSupportingLogicalSession)) { + if (serverSupports(kWireVersionSupportingLogicalSession) && + // Always attach sessionId from explicit sessions. + (driverSession._isExplicit || + // Check that implicit sessions are not disabled. The client must be using read + // commands because aggregations always use runCommand() to establish cursors but + // may use OP_GET_MORE (and therefore not have a session id attached) to retrieve + // subsequent batches. + (!jsTest.options().disableImplicitSessions && client.useReadCommands()))) { cmdObj = driverSession._serverSession.injectSessionId(cmdObj); } @@ -591,6 +598,8 @@ var { this._serverSession = implMethods.createServerSession(client); + this._isExplicit = true; + this.getClient = function getClient() { return client; }; diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp index c13f6291636..196e4060523 100644 --- a/src/mongo/shell/shell_utils.cpp +++ b/src/mongo/shell/shell_utils.cpp @@ -217,6 +217,10 @@ BSONObj shouldRetryWrites(const BSONObj&, void* data) { return BSON("" << shellGlobalParams.shouldRetryWrites); } +BSONObj shouldUseImplicitSessions(const BSONObj&, void* data) { + return BSON("" << true); +} + BSONObj interpreterVersion(const BSONObj& a, void* data) { uassert(16453, "interpreterVersion accepts no arguments", a.nFields() == 0); return BSON("" << getGlobalScriptEngine()->getInterpreterVersionString()); @@ -253,6 +257,7 @@ void initScope(Scope& scope) { scope.injectNative("_writeMode", writeMode); scope.injectNative("_readMode", readMode); scope.injectNative("_shouldRetryWrites", shouldRetryWrites); + scope.injectNative("_shouldUseImplicitSessions", shouldUseImplicitSessions); scope.externalSetup(); mongo::shell_utils::installShellUtils(scope); scope.execSetup(JSFiles::servers); diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js index c6c00fcf0ac..edcd73f1b0c 100644 --- a/src/mongo/shell/utils.js +++ b/src/mongo/shell/utils.js @@ -298,6 +298,7 @@ jsTestOptions = function() { logRetryAttempts: TestData.logRetryAttempts || false, connectionString: TestData.connectionString || "", skipCheckDBHashes: TestData.skipCheckDBHashes || false, + disableImplicitSessions: TestData.disableImplicitSessions || false, }); } return _jsTestOptions; @@ -543,6 +544,16 @@ if (typeof _shouldRetryWrites === 'undefined') { }; } +if (typeof _shouldUseImplicitSessions === 'undefined') { + // We ensure the _shouldUseImplicitSessions() function is always defined, in case the JavaScript + // engine is being used from someplace other than the mongo shell (e.g. map-reduce). If the + // function was not defined, implicit sessions are disabled to prevent unnecessary sessions from + // being created. + _shouldUseImplicitSessions = function _shouldUseImplicitSessions() { + return false; + }; +} + shellPrintHelper = function(x) { if (typeof(x) == "undefined") { // Make sure that we have a db var before we use it |