diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2017-11-30 10:16:32 -0500 |
---|---|---|
committer | Sara Golemon <sara.golemon@mongodb.com> | 2017-12-01 16:29:40 -0500 |
commit | 4a5f07ba38561db71727fe4254de5e9c24053645 (patch) | |
tree | c11ead2d7bb621670387798b34f038efd047735e | |
parent | bd20a3fe5a8aea410282f25f7dacdf7bb923b7c0 (diff) | |
download | mongo-4a5f07ba38561db71727fe4254de5e9c24053645.tar.gz |
SERVER-30491 Remove CRAM-MD5
-rw-r--r-- | jstests/auth/auth_helpers.js | 73 | ||||
-rw-r--r-- | src/mongo/client/sasl_sspi.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/auth/SConscript | 17 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_authentication_session.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_authentication_session.h | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_authentication_session_test.cpp | 236 |
6 files changed, 265 insertions, 85 deletions
diff --git a/jstests/auth/auth_helpers.js b/jstests/auth/auth_helpers.js index 94131821784..fd2775cc463 100644 --- a/jstests/auth/auth_helpers.js +++ b/jstests/auth/auth_helpers.js @@ -1,65 +1,28 @@ // Test the db.auth() shell helper. -// -// This test requires users to persist across a restart. -// @tags: [requires_persistence] -var conn = MongoRunner.runMongod({smallfiles: ""}); +(function() { + 'use strict'; -var mechanisms, hasCR, hasCramMd5; + const conn = MongoRunner.runMongod({smallfiles: ""}); + const admin = conn.getDB('admin'); -var admin = conn.getDB('admin'); -// In order to test MONGODB-CR we need to "reset" the authSchemaVersion to -// 26Final "3" or else the user won't get MONGODB-CR credentials. -admin.system.version.save({"_id": "authSchema", "currentVersion": 3}); -admin.createUser({user: 'andy', pwd: 'a', roles: jsTest.adminUserRoles}); -admin.auth({user: 'andy', pwd: 'a'}); - -// Attempt to start with CRAM-MD5 enabled -// If this fails the build only supports default auth mechanisms -MongoRunner.stopMongod(conn); -var restartedConn = MongoRunner.runMongod({ - auth: "", - restart: conn, - setParameter: "authenticationMechanisms=SCRAM-SHA-1,MONGODB-CR,CRAM-MD5" -}); -if (restartedConn != null) { - mechanisms = ["SCRAM-SHA-1", "MONGODB-CR", "CRAM-MD5"]; - hasCR = true; - hasCramMd5 = true; - print("test info: Enabling non-default authentication mechanisms."); -} else { - restartedConn = MongoRunner.runMongod({restart: conn}); - mechanisms = ["SCRAM-SHA-1", "MONGODB-CR"]; - hasCR = true; - hasCramMd5 = false; - print("test info: Using only default password authentication mechanisms."); -} - -admin = restartedConn.getDB('admin'); -var testedSomething = false; + // In order to test MONGODB-CR we need to "reset" the authSchemaVersion to + // 26Final "3" or else the user won't get MONGODB-CR credentials. + admin.system.version.save({"_id": "authSchema", "currentVersion": 3}); + admin.createUser({user: 'andy', pwd: 'a', roles: jsTest.adminUserRoles}); + assert(admin.auth({user: 'andy', pwd: 'a'})); + assert(admin.logout()); -// Try all the ways to call db.auth that uses SCRAM-SHA-1 or MONGODB-CR. -if (hasCR) { - testedSomething = true; + // Try all the ways to call db.auth that uses SCRAM-SHA-1 or MONGODB-CR. assert(admin.auth('andy', 'a')); - admin.logout(); + assert(admin.logout()); assert(admin.auth({user: 'andy', pwd: 'a'})); - admin.logout(); + assert(admin.logout()); assert(admin.auth({mechanism: 'SCRAM-SHA-1', user: 'andy', pwd: 'a'})); - admin.logout(); + assert(admin.logout()); assert(admin.auth({mechanism: 'MONGODB-CR', user: 'andy', pwd: 'a'})); - admin.logout(); -} - -// If the server supports CRAM-MD5, try it out. -if (hasCramMd5) { - testedSomething = true; - assert(admin.auth({mechanism: 'CRAM-MD5', user: 'andy', pwd: 'a'})); - admin.logout(); -} - -// Sanity check that we tested at least one of MONGODB-CR and CRAM-MD5. -assert(testedSomething, "No candidate authentication mechanisms matched."); + assert(admin.logout()); -// Invalid mechanisms shouldn't lead to authentication, but also shouldn't crash. -assert(!admin.auth({mechanism: 'this-mechanism-is-fake', user: 'andy', pwd: 'a'})); + // Invalid mechanisms shouldn't lead to authentication, but also shouldn't crash. + assert(!admin.auth({mechanism: 'this-mechanism-is-fake', user: 'andy', pwd: 'a'})); +})(); diff --git a/src/mongo/client/sasl_sspi.cpp b/src/mongo/client/sasl_sspi.cpp index 954746c211e..de8afc7bafa 100644 --- a/src/mongo/client/sasl_sspi.cpp +++ b/src/mongo/client/sasl_sspi.cpp @@ -52,12 +52,6 @@ extern "C" int plain_client_plug_init(const sasl_utils_t* utils, sasl_client_plug_t** pluglist, int* plugcount); -extern "C" int crammd5_client_plug_init(const sasl_utils_t* utils, - int maxversion, - int* out_version, - sasl_client_plug_t** pluglist, - int* plugcount); - namespace mongo { namespace { /* @@ -494,20 +488,6 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SaslSspiClientPlugin, return Status::OK(); } -MONGO_INITIALIZER_WITH_PREREQUISITES(SaslCramClientPlugin, - ("CyrusSaslAllocatorsAndMutexes", "CyrusSaslClientContext")) -(InitializerContext*) { - int ret = sasl_client_add_plugin("CRAMMD5", crammd5_client_plug_init); - if (SASL_OK != ret) { - return Status(ErrorCodes::UnknownError, - mongoutils::str::stream() << "Could not add SASL Client CRAM-MD5 plugin " - << sspiPluginName - << ": " - << sasl_errstring(ret, NULL, NULL)); - } - - return Status::OK(); -} MONGO_INITIALIZER_WITH_PREREQUISITES(SaslPlainClientPlugin, ("CyrusSaslAllocatorsAndMutexes", "CyrusSaslClientContext")) diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index 043641da879..f70297efbf3 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -294,10 +294,15 @@ env.CppUnitTest( ], ) -env.CppUnitTest('sasl_scramsha1_test', - 'sasl_scramsha1_test.cpp', - LIBDEPS=[ - 'saslauth', - '$BUILD_DIR/mongo/client/sasl_client', - ]) +env.CppUnitTest( + target='sasl_scramsha1_test', + source=[ + 'sasl_authentication_session_test.cpp', + 'sasl_scramsha1_test.cpp', + ], + LIBDEPS_PRIVATE=[ + 'saslauth', + '$BUILD_DIR/mongo/client/sasl_client', + ], +) diff --git a/src/mongo/db/auth/sasl_authentication_session.cpp b/src/mongo/db/auth/sasl_authentication_session.cpp index e449c6a7ae8..b2679702da7 100644 --- a/src/mongo/db/auth/sasl_authentication_session.cpp +++ b/src/mongo/db/auth/sasl_authentication_session.cpp @@ -49,8 +49,6 @@ namespace mongo { SaslAuthenticationSession::SaslAuthenticationSessionFactoryFn SaslAuthenticationSession::create; // Mechanism name constants. -const char SaslAuthenticationSession::mechanismCRAMMD5[] = "CRAM-MD5"; -const char SaslAuthenticationSession::mechanismDIGESTMD5[] = "DIGEST-MD5"; const char SaslAuthenticationSession::mechanismSCRAMSHA1[] = "SCRAM-SHA-1"; const char SaslAuthenticationSession::mechanismGSSAPI[] = "GSSAPI"; const char SaslAuthenticationSession::mechanismPLAIN[] = "PLAIN"; diff --git a/src/mongo/db/auth/sasl_authentication_session.h b/src/mongo/db/auth/sasl_authentication_session.h index adaea792284..621ccd1fd3c 100644 --- a/src/mongo/db/auth/sasl_authentication_session.h +++ b/src/mongo/db/auth/sasl_authentication_session.h @@ -57,8 +57,6 @@ public: static SaslAuthenticationSessionFactoryFn create; // Mechanism name constants. - static const char mechanismCRAMMD5[]; - static const char mechanismDIGESTMD5[]; static const char mechanismSCRAMSHA1[]; static const char mechanismGSSAPI[]; static const char mechanismPLAIN[]; diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp new file mode 100644 index 00000000000..355ccda35fa --- /dev/null +++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2013 10gen, Inc. All Rights Reserved. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kAccessControl + +#include <string> +#include <vector> + +#include "mongo/bson/mutable/algorithm.h" +#include "mongo/bson/mutable/document.h" +#include "mongo/bson/mutable/element.h" +#include "mongo/client/sasl_client_session.h" +#include "mongo/crypto/mechanism_scram.h" +#include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/authz_manager_external_state_mock.h" +#include "mongo/db/auth/authz_session_external_state_mock.h" +#include "mongo/db/auth/sasl_authentication_session.h" +#include "mongo/db/auth/sasl_options.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/operation_context_noop.h" +#include "mongo/platform/unordered_map.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/log.h" +#include "mongo/util/password_digest.h" + +namespace mongo { + +namespace { + +class SaslConversation : public unittest::Test { +public: + explicit SaslConversation(std::string mech); + + void testSuccessfulAuthentication(); + void testNoSuchUser(); + void testBadPassword(); + void testWrongClientMechanism(); + void testWrongServerMechanism(); + + AuthzManagerExternalStateMock* authManagerExternalState; + AuthorizationManager authManager; + std::unique_ptr<AuthorizationSession> authSession; + std::string mechanism; + std::unique_ptr<SaslClientSession> client; + std::unique_ptr<SaslAuthenticationSession> server; + +private: + void assertConversationFailure(); +}; + +class SaslIllegalConversation : public SaslConversation { +public: + SaslIllegalConversation() : SaslConversation("ILLEGAL") {} +}; + +const std::string mockServiceName = "mocksvc"; +const std::string mockHostName = "host.mockery.com"; + +SaslConversation::SaslConversation(std::string mech) + : authManagerExternalState(new AuthzManagerExternalStateMock), + authManager(std::unique_ptr<AuthzManagerExternalState>(authManagerExternalState)), + authSession(authManager.makeAuthorizationSession()), + mechanism(mech) { + OperationContextNoop opCtx; + + client.reset(SaslClientSession::create(mechanism)); + server.reset(SaslAuthenticationSession::create(authSession.get(), "test", mechanism)); + + ASSERT_OK(authManagerExternalState->updateOne( + &opCtx, + AuthorizationManager::versionCollectionNamespace, + AuthorizationManager::versionDocumentQuery, + BSON("$set" << BSON(AuthorizationManager::schemaVersionFieldName + << AuthorizationManager::schemaVersion26Final)), + true, + BSONObj())); + + const auto authHash = (mech == "SCRAM-SHA-1") ? "frim" : createPasswordDigest("andy", "frim"); + const auto creds = BSON("SCRAM-SHA-1" << scram::generateCredentials( + authHash, saslGlobalParams.scramIterationCount.load())); + + ASSERT_OK(authManagerExternalState->insert(&opCtx, + NamespaceString("admin.system.users"), + BSON("_id" + << "test.andy" + << "user" + << "andy" + << "db" + << "test" + << "credentials" + << creds + << "roles" + << BSONArray()), + BSONObj())); +} + +void SaslConversation::assertConversationFailure() { + std::string clientMessage; + std::string serverMessage; + Status clientStatus(ErrorCodes::InternalError, ""); + Status serverStatus(ErrorCodes::InternalError, ""); + do { + clientStatus = client->step(serverMessage, &clientMessage); + if (!clientStatus.isOK()) + break; + serverStatus = server->step(clientMessage, &serverMessage); + if (!serverStatus.isOK()) + break; + } while (!client->isDone()); + ASSERT_FALSE(serverStatus.isOK() && clientStatus.isOK() && client->isDone() && + server->isDone()); +} + +void SaslConversation::testSuccessfulAuthentication() { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, mechanism); + client->setParameter(SaslClientSession::parameterUser, "andy"); + client->setParameter(SaslClientSession::parameterPassword, "frim"); + ASSERT_OK(client->initialize()); + + ASSERT_OK(server->start("test", mechanism, mockServiceName, mockHostName, 1, true)); + + std::string clientMessage; + std::string serverMessage; + do { + ASSERT_OK(client->step(serverMessage, &clientMessage)); + ASSERT_OK(server->step(clientMessage, &serverMessage)); + } while (!client->isDone()); + ASSERT_TRUE(server->isDone()); +} + +void SaslConversation::testNoSuchUser() { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, mechanism); + client->setParameter(SaslClientSession::parameterUser, "nobody"); + client->setParameter(SaslClientSession::parameterPassword, "frim"); + ASSERT_OK(client->initialize()); + + ASSERT_OK(server->start("test", mechanism, mockServiceName, mockHostName, 1, true)); + + assertConversationFailure(); +} + +void SaslConversation::testBadPassword() { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, mechanism); + client->setParameter(SaslClientSession::parameterUser, "andy"); + client->setParameter(SaslClientSession::parameterPassword, "WRONG"); + ASSERT_OK(client->initialize()); + + ASSERT_OK(server->start("test", mechanism, mockServiceName, mockHostName, 1, true)); + + + assertConversationFailure(); +} + +void SaslConversation::testWrongClientMechanism() { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, + mechanism != "SCRAM-SHA-1" ? "SCRAM-SHA-1" : "PLAIN"); + client->setParameter(SaslClientSession::parameterUser, "andy"); + client->setParameter(SaslClientSession::parameterPassword, "frim"); + ASSERT_OK(client->initialize()); + + ASSERT_OK(server->start("test", mechanism, mockServiceName, mockHostName, 1, true)); + + assertConversationFailure(); +} + +void SaslConversation::testWrongServerMechanism() { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, mechanism); + client->setParameter(SaslClientSession::parameterUser, "andy"); + client->setParameter(SaslClientSession::parameterPassword, "frim"); + ASSERT_OK(client->initialize()); + + ASSERT_OK(server->start("test", + mechanism != "SCRAM-SHA-1" ? "SCRAM-SHA-1" : "PLAIN", + mockServiceName, + mockHostName, + 1, + true)); + assertConversationFailure(); +} + +#define DEFINE_MECHANISM_FIXTURE(CLASS_SUFFIX, MECH_NAME) \ + class SaslConversation##CLASS_SUFFIX : public SaslConversation { \ + public: \ + SaslConversation##CLASS_SUFFIX() : SaslConversation(MECH_NAME) {} \ + } + +#define DEFINE_MECHANISM_TEST(FIXTURE_NAME, TEST_NAME) \ + TEST_F(FIXTURE_NAME, TEST_NAME) { \ + test##TEST_NAME(); \ + } + +#define DEFINE_ALL_MECHANISM_TESTS(FIXTURE_NAME) \ + DEFINE_MECHANISM_TEST(FIXTURE_NAME, SuccessfulAuthentication) \ + DEFINE_MECHANISM_TEST(FIXTURE_NAME, NoSuchUser) \ + DEFINE_MECHANISM_TEST(FIXTURE_NAME, BadPassword) \ + DEFINE_MECHANISM_TEST(FIXTURE_NAME, WrongClientMechanism) \ + DEFINE_MECHANISM_TEST(FIXTURE_NAME, WrongServerMechanism) + +#define TEST_MECHANISM(CLASS_SUFFIX, MECH_NAME) \ + DEFINE_MECHANISM_FIXTURE(CLASS_SUFFIX, MECH_NAME); \ + DEFINE_ALL_MECHANISM_TESTS(SaslConversation##CLASS_SUFFIX) + +TEST_MECHANISM(SCRAMSHA1, "SCRAM-SHA-1") +TEST_MECHANISM(PLAIN, "PLAIN") + +TEST_F(SaslIllegalConversation, IllegalClientMechanism) { + client->setParameter(SaslClientSession::parameterServiceName, mockServiceName); + client->setParameter(SaslClientSession::parameterServiceHostname, mockHostName); + client->setParameter(SaslClientSession::parameterMechanism, "FAKE"); + client->setParameter(SaslClientSession::parameterUser, "andy"); + client->setParameter(SaslClientSession::parameterPassword, "frim"); + + std::string clientMessage; + std::string serverMessage; + ASSERT(!client->initialize().isOK() || !client->step(serverMessage, &clientMessage).isOK()); +} + +TEST_F(SaslIllegalConversation, IllegalServerMechanism) { + ASSERT_NOT_OK(server->start("test", "FAKE", mockServiceName, mockHostName, 1, true)); +} + +} // namespace + +} // namespace mongo |