diff options
author | Andreas Nilsson <andreas.nilsson@10gen.com> | 2014-10-07 16:59:05 -0400 |
---|---|---|
committer | Andreas Nilsson <andreas.nilsson@10gen.com> | 2014-10-10 09:55:13 -0400 |
commit | eb3435c25eabc90e2c4ff7c331c94c4c222d0b7e (patch) | |
tree | 63b73d91f489eacd599035e417cff62998ef8a0e | |
parent | b179fa1eab1bc79be8562349ca6f43283f16ecc7 (diff) | |
download | mongo-eb3435c25eabc90e2c4ff7c331c94c4c222d0b7e.tar.gz |
SERVER-15236 Using SCRAM-SHA-1 for keyfile authentication
-rwxr-xr-x | buildscripts/smoke.py | 2 | ||||
-rw-r--r-- | buildscripts/smoke_config/auth.yaml | 4 | ||||
-rw-r--r-- | buildscripts/smoke_config/auth_shell.yaml | 4 | ||||
-rw-r--r-- | jstests/auth/copyauth.js | 4 | ||||
-rw-r--r-- | src/mongo/crypto/mechanism_scram.cpp | 8 | ||||
-rw-r--r-- | src/mongo/crypto/mechanism_scram.h | 6 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_commands.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/auth/security_key.cpp | 65 | ||||
-rw-r--r-- | src/mongo/shell/shardingtest.js | 2 | ||||
-rw-r--r-- | src/mongo/shell/utils_auth.js | 2 |
11 files changed, 84 insertions, 33 deletions
diff --git a/buildscripts/smoke.py b/buildscripts/smoke.py index d8884c6e3dc..fa00b907a12 100755 --- a/buildscripts/smoke.py +++ b/buildscripts/smoke.py @@ -1242,7 +1242,7 @@ def main(): parser.add_option('--use-x509', dest='use_x509', default=False, action="store_true", help='Use x509 auth for internal cluster authentication') - parser.add_option('--authMechanism', dest='authMechanism', default='MONGODB-CR', + parser.add_option('--authMechanism', dest='authMechanism', default='SCRAM-SHA-1', help='Use the given authentication mechanism, when --auth is used.') parser.add_option('--keyFile', dest='keyFile', default=None, help='Path to keyFile to use to run replSet and sharding tests with authentication enabled') diff --git a/buildscripts/smoke_config/auth.yaml b/buildscripts/smoke_config/auth.yaml index 102c8721b3f..9f4660fa831 100644 --- a/buildscripts/smoke_config/auth.yaml +++ b/buildscripts/smoke_config/auth.yaml @@ -14,14 +14,14 @@ executor: shell_globals: TestData: auth: true - authMechanism: MONGODB-CR + authMechanism: SCRAM-SHA-1 keyFile: ./jstests/lib/authTestsKey keyFileData: Thiskeyisonlyforrunningthesuitewithauthenticationdontuseitinanytestsdirectly testers: js_test: shell_options: authenticationDatabase: local - authenticationMechanism: MONGODB-CR + authenticationMechanism: SCRAM-SHA-1 password: Thiskeyisonlyforrunningthesuitewithauthenticationdontuseitinanytestsdirectly username: __system diff --git a/buildscripts/smoke_config/auth_shell.yaml b/buildscripts/smoke_config/auth_shell.yaml index 56388ebb555..b89b776cfd8 100644 --- a/buildscripts/smoke_config/auth_shell.yaml +++ b/buildscripts/smoke_config/auth_shell.yaml @@ -8,14 +8,14 @@ executor: shell_globals: TestData: auth: true - authMechanism: MONGODB-CR + authMechanism: SCRAM-SHA-1 keyFile: ./jstests/lib/authTestsKey keyFileData: Thiskeyisonlyforrunningthesuitewithauthenticationdontuseitinanytestsdirectly testers: js_test: shell_options: authenticationDatabase: local - authenticationMechanism: MONGODB-CR + authenticationMechanism: SCRAM-SHA-1 password: Thiskeyisonlyforrunningthesuitewithauthenticationdontuseitinanytestsdirectly username: __system diff --git a/jstests/auth/copyauth.js b/jstests/auth/copyauth.js index 1148b31104e..bf1742ea598 100644 --- a/jstests/auth/copyauth.js +++ b/jstests/auth/copyauth.js @@ -1,8 +1,8 @@ // Test copyDatabase command with various combinations of authed/unauthed and single node/replica // set source and dest. -TestData.authMechanism = "MONGODB-CR"; // SERVER-11428 -DB.prototype._defaultAuthenticationMechanism = "MONGODB-CR"; // SERVER-11428 +TestData.authMechanism = "SCRAM-SHA-1"; // SERVER-11428 +DB.prototype._defaultAuthenticationMechanism = "SCRAM-SHA-1"; // SERVER-11428 var baseName = "jstests_clone_copyauth"; diff --git a/src/mongo/crypto/mechanism_scram.cpp b/src/mongo/crypto/mechanism_scram.cpp index 95629fcae86..1b6eaf88ea9 100644 --- a/src/mongo/crypto/mechanism_scram.cpp +++ b/src/mongo/crypto/mechanism_scram.cpp @@ -171,10 +171,10 @@ namespace scram { std::string encodedServerKey = base64::encode(reinterpret_cast<char*>(serverKey), hashSize); - return BSON("iterationCount" << iterationCount << - "salt" << encodedUserSalt << - "storedKey" << encodedStoredKey << - "serverKey" << encodedServerKey); + return BSON(iterationCountFieldName << iterationCount << + saltFieldName << encodedUserSalt << + storedKeyFieldName << encodedStoredKey << + serverKeyFieldName << encodedServerKey); } std::string generateClientProof(const unsigned char saltedPassword[hashSize], diff --git a/src/mongo/crypto/mechanism_scram.h b/src/mongo/crypto/mechanism_scram.h index 6f5b37b8d6b..fc6da4aea9c 100644 --- a/src/mongo/crypto/mechanism_scram.h +++ b/src/mongo/crypto/mechanism_scram.h @@ -36,9 +36,15 @@ namespace mongo { namespace scram { const unsigned int hashSize = 20; + const std::string serverKeyConst = "Server Key"; const std::string clientKeyConst = "Client Key"; + const std::string iterationCountFieldName = "iterationCount"; + const std::string saltFieldName = "salt"; + const std::string storedKeyFieldName = "storedKey"; + const std::string serverKeyFieldName = "serverKey"; + /* * Computes the SaltedPassword from password, salt and iterationCount. */ diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp index be9543a33da..14dfcc02e5d 100644 --- a/src/mongo/db/auth/sasl_commands.cpp +++ b/src/mongo/db/auth/sasl_commands.cpp @@ -323,7 +323,9 @@ namespace { SaslAuthenticationSession* session = static_cast<SaslAuthenticationSession*>(sessionGuard.get()); - if (session->getAuthenticationDatabase() != db) { + // Authenticating the __system@local user to the admin database on mongos is required + // by the auth passthrough test suite. + if (session->getAuthenticationDatabase() != db && !Command::testCommandsEnabled) { addStatus(Status(ErrorCodes::ProtocolError, "Attempt to switch database target during SASL authentication."), &result); @@ -348,18 +350,18 @@ namespace { return status.isOK(); } - + // The CyrusSaslCommands Enterprise initializer is dependent on PreSaslCommands MONGO_INITIALIZER_WITH_PREREQUISITES(PreSaslCommands, ("NativeSaslServerCore")) (InitializerContext*) { - + if (!sequenceContains(saslGlobalParams.authenticationMechanisms, "MONGODB-CR")) CmdAuthenticate::disableAuthMechanism("MONGODB-CR"); - + if (!sequenceContains(saslGlobalParams.authenticationMechanisms, "MONGODB-X509")) CmdAuthenticate::disableAuthMechanism("MONGODB-X509"); - + return Status::OK(); } diff --git a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp index 7631372bd17..791fe137b11 100644 --- a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp +++ b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp @@ -159,10 +159,10 @@ namespace mongo { // Generate SCRAM credentials on the fly for mixed MONGODB-CR/SCRAM mode. if (_creds.scram.salt.empty() && !_creds.password.empty()) { BSONObj scramCreds = scram::generateCredentials(_creds.password); - _creds.scram.iterationCount = scramCreds["iterationCount"].Int(); - _creds.scram.salt = scramCreds["salt"].String(); - _creds.scram.storedKey = scramCreds["storedKey"].String(); - _creds.scram.serverKey = scramCreds["serverKey"].String(); + _creds.scram.iterationCount = scramCreds[scram::iterationCountFieldName].Int(); + _creds.scram.salt = scramCreds[scram::saltFieldName].String(); + _creds.scram.storedKey = scramCreds[scram::storedKeyFieldName].String(); + _creds.scram.serverKey = scramCreds[scram::serverKeyFieldName].String(); } // Generate server-first-message diff --git a/src/mongo/db/auth/security_key.cpp b/src/mongo/db/auth/security_key.cpp index 221a0c48cf5..dcc0f7866a3 100644 --- a/src/mongo/db/auth/security_key.cpp +++ b/src/mongo/db/auth/security_key.cpp @@ -36,7 +36,10 @@ #include <string> #include <vector> +#include "mongo/bson/mutable/document.h" +#include "mongo/bson/mutable/element.h" #include "mongo/client/sasl_client_authenticate.h" +#include "mongo/crypto/mechanism_scram.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -47,15 +50,22 @@ #include "mongo/util/password_digest.h" namespace mongo { + namespace mmb = mongo::mutablebson; + // not guarded by the authParams mutex never changed in // multi-threaded operation static bool authParamsSet = false; + + // Store default authentication parameters for internal authentication to cluster members, // guarded by the authParams mutex static BSONObj authParams; - static boost::mutex authParamMutex; + + // Store MONGODB-CR authentication parameters to use as fallback for mixed 2.6/28 clusters + static BSONObj authParamsCR; + static boost::mutex authParamMutex; bool isInternalAuthSet() { - return authParamsSet; + return authParamsSet; } void setInternalUserAuthParams(const BSONObj& authParamsIn) { @@ -64,20 +74,45 @@ namespace mongo { } boost::mutex::scoped_lock lk(authParamMutex); authParams = authParamsIn.copy(); + + // Create authParams for legacy MONGODB-CR authentication if applicable. + if (authParams["mechanism"].String() == "SCRAM-SHA-1") { + mmb::Document doc(authParams); + doc.root().findFirstChildNamed("mechanism").setValueString("MONGODB-CR"); + authParamsCR = doc.getObject().copy(); + } } - + bool authenticateInternalUser(DBClientWithCommands* conn){ if (!isInternalAuthSet()) { log() << "ERROR: No authentication parameters set for internal user" << endl; return false; } - try { - BSONObj outgoingAuthParams; - { - boost::mutex::scoped_lock lk(authParamMutex); - outgoingAuthParams = authParams.copy(); - } - conn->auth(outgoingAuthParams); + + BSONObj authParamsCopy; + BSONObj authParamsCRCopy; + { + boost::mutex::scoped_lock lk(authParamMutex); + authParamsCopy = authParams.copy(); + authParamsCRCopy = authParamsCR.copy(); + } + + try { + conn->auth(authParamsCopy); + return true; + } catch(const UserException& ex) { + if (ex.getCode() != ErrorCodes::BadValue && + ex.getCode() != ErrorCodes::CommandNotFound) { + log() << "can't authenticate to " << conn->toString() << + " as internal user, error: "<< ex.what() << endl; + return false; + } + } + + // BadValue indicates unsupported auth mechanism so fall back to + // MONGODB-CR for 2.6 compatibility. + try { + conn->auth(authParamsCRCopy); return true; } catch(const UserException& ex) { log() << "can't authenticate to " << conn->toString() << " as internal user, error: " @@ -148,16 +183,24 @@ namespace mongo { return false; } + // Generate MONGODB-CR and SCRAM credentials for the internal user based on the keyfile. User::CredentialData credentials; credentials.password = mongo::createPasswordDigest( internalSecurity.user->getName().getUser().toString(), str); + + BSONObj creds = scram::generateCredentials(credentials.password); + credentials.scram.iterationCount = creds[scram::iterationCountFieldName].Int(); + credentials.scram.salt = creds[scram::saltFieldName].String(); + credentials.scram.storedKey = creds[scram::storedKeyFieldName].String(); + credentials.scram.serverKey = creds[scram::serverKeyFieldName].String(); + internalSecurity.user->setCredentials(credentials); int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_keyFile || clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile) { setInternalUserAuthParams( - BSON(saslCommandMechanismFieldName << "MONGODB-CR" << + BSON(saslCommandMechanismFieldName << "SCRAM-SHA-1" << saslCommandUserDBFieldName << internalSecurity.user->getName().getDB() << saslCommandUserFieldName << internalSecurity.user->getName().getUser() << diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js index 1c8241ec392..3e333ab898d 100644 --- a/src/mongo/shell/shardingtest.js +++ b/src/mongo/shell/shardingtest.js @@ -386,7 +386,7 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other if (keyFile) { authutil.assertAuthenticate(this._mongos, 'admin', { user: '__system', - mechanism: 'MONGODB-CR', + mechanism: 'SCRAM-SHA-1', pwd: cat(keyFile).replace(/[\011-\015\040]/g, '') }); diff --git a/src/mongo/shell/utils_auth.js b/src/mongo/shell/utils_auth.js index ff8f1543cac..f8534f616b1 100644 --- a/src/mongo/shell/utils_auth.js +++ b/src/mongo/shell/utils_auth.js @@ -71,7 +71,7 @@ var authutil; var ex; authutil.assertAuthenticate(conn, 'local', { user: '__system', - mechanism: 'MONGODB-CR', + mechanism: 'SCRAM-SHA-1', pwd: cat(keyfile).replace(/[\011-\015\040]/g, '') }); |