diff options
-rw-r--r-- | jstests/auth/auth_mechanism_discovery.js | 43 | ||||
-rw-r--r-- | src/mongo/shell/db.js | 37 |
2 files changed, 73 insertions, 7 deletions
diff --git a/jstests/auth/auth_mechanism_discovery.js b/jstests/auth/auth_mechanism_discovery.js new file mode 100644 index 00000000000..e613adff8c3 --- /dev/null +++ b/jstests/auth/auth_mechanism_discovery.js @@ -0,0 +1,43 @@ +// Tests that a client will auto-discover a user's supported SASL mechanisms during auth(). +(function() { + "use strict"; + + function runTest(conn) { + const admin = conn.getDB("admin"); + const test = conn.getDB("test"); + + admin.createUser({user: 'admin', pwd: 'pass', roles: jsTest.adminUserRoles}); + assert(admin.auth('admin', 'pass')); + + // Enable SCRAM-SHA-256. + assert.commandWorked(admin.runCommand({setFeatureCompatibilityVersion: "4.0"})); + + function checkUser(username, mechanism) { + var createUser = {createUser: username, pwd: 'pwd', roles: []}; + if (mechanism !== undefined) { + createUser.mechanisms = [mechanism]; + } else { + // Create both variants, expect to prefer 256. + mechanism = 'SCRAM-SHA-256'; + } + assert.commandWorked(test.runCommand(createUser)); + assert.eq(test._getDefaultAuthenticationMechanism(username, test.getName()), mechanism); + assert(test.auth(username, 'pwd')); + test.logout(); + } + checkUser('userSha1', 'SCRAM-SHA-1'); + checkUser('userSha256', 'SCRAM-SHA-256'); + checkUser('userAll'); + } + + // Test standalone. + const m = MongoRunner.runMongod({auth: ""}); + runTest(m); + MongoRunner.stopMongod(m); + + // Test sharded. + const st = + new ShardingTest({shards: 1, mongos: 1, config: 1, other: {keyFile: 'jstests/libs/key1'}}); + runTest(st.s0); + st.stop(); +})(); diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index ca0048c301a..4493b2a1192 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -544,9 +544,10 @@ var DB; } if (!mechanism) { - mechanism = this._getDefaultAuthenticationMechanism(); + mechanism = this._getDefaultAuthenticationMechanism(username, fromdb); } - assert(mechanism == "SCRAM-SHA-1" || mechanism == "MONGODB-CR"); + assert(mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" || + mechanism == "MONGODB-CR"); // Check for no auth or copying from localhost if (!username || !password || fromhost == "") { @@ -554,8 +555,8 @@ var DB; {copydb: 1, fromhost: fromhost, fromdb: fromdb, todb: todb, slaveOk: slaveOk}); } - // Use the copyDatabase native helper for SCRAM-SHA-1 - if (mechanism == "SCRAM-SHA-1") { + // Use the copyDatabase native helper for SCRAM-SHA-1/256 + if (mechanism != "MONGODB-CR") { // TODO SERVER-30886: Add session support for Mongo.prototype.copyDatabaseWithSCRAM(). return this.getMongo().copyDatabaseWithSCRAM( fromdb, todb, fromhost, username, password, slaveOk); @@ -1563,7 +1564,28 @@ var DB; DB.prototype._defaultAuthenticationMechanism = null; - DB.prototype._getDefaultAuthenticationMechanism = function() { + DB.prototype._getDefaultAuthenticationMechanism = function(username, database) { + if (username !== undefined) { + const userid = database + "." + username; + const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid}); + if (result.ok && (result.saslSupportedMechs !== undefined)) { + const mechs = result.saslSupportedMechs; + if (!Array.isArray(mechs)) { + throw Error("Server replied with invalid saslSupportedMechs response"); + } + // Never include PLAIN in auto-negotiation. + const priority = ["GSSAPI", "SCRAM-SHA-256", "SCRAM-SHA-1"]; + for (var i = 0; i < priority.length; ++i) { + if (mechs.includes(priority[i])) { + return priority[i]; + } + } + } + // If isMaster doesn't support saslSupportedMechs, + // or if we couldn't agree on a mechanism, + // then fallthrough to configured default or SCRAM-SHA-1. + } + // Use the default auth mechanism if set on the command line. if (this._defaultAuthenticationMechanism != null) return this._defaultAuthenticationMechanism; @@ -1586,8 +1608,9 @@ var DB; "auth expects either (username, password) or ({ user: username, pwd: password })"); } - if (params.mechanism === undefined) - params.mechanism = this._getDefaultAuthenticationMechanism(); + if (params.mechanism === undefined) { + params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName()); + } if (params.db !== undefined) { throw Error("Do not override db field on db.auth(). Use getMongo().auth(), instead."); |