summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2017-11-30 10:16:32 -0500
committerSara Golemon <sara.golemon@mongodb.com>2017-12-01 16:29:40 -0500
commit4a5f07ba38561db71727fe4254de5e9c24053645 (patch)
treec11ead2d7bb621670387798b34f038efd047735e
parentbd20a3fe5a8aea410282f25f7dacdf7bb923b7c0 (diff)
downloadmongo-4a5f07ba38561db71727fe4254de5e9c24053645.tar.gz
SERVER-30491 Remove CRAM-MD5
-rw-r--r--jstests/auth/auth_helpers.js73
-rw-r--r--src/mongo/client/sasl_sspi.cpp20
-rw-r--r--src/mongo/db/auth/SConscript17
-rw-r--r--src/mongo/db/auth/sasl_authentication_session.cpp2
-rw-r--r--src/mongo/db/auth/sasl_authentication_session.h2
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp236
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