From 09c727b590720420f3cb206fe53931810638c336 Mon Sep 17 00:00:00 2001 From: Mark Benvenuto Date: Mon, 20 Apr 2020 14:34:56 -0400 Subject: SERVER-47429 Validate authenticationMechanisms server parameter (cherry picked from commit 817a7f1951189b2a8c7c06fb5fb5361241c1cd57) --- jstests/auth/validate_sasl_mechanism.js | 23 ++++++++++++++ src/mongo/db/auth/sasl_mechanism_registry.cpp | 43 +++++++++++++++++++++++++++ src/mongo/db/auth/sasl_mechanism_registry.h | 3 ++ src/mongo/db/service_context.cpp | 12 +++++++- src/mongo/db/service_context.h | 17 +++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 jstests/auth/validate_sasl_mechanism.js diff --git a/jstests/auth/validate_sasl_mechanism.js b/jstests/auth/validate_sasl_mechanism.js new file mode 100644 index 00000000000..cae29ae83b0 --- /dev/null +++ b/jstests/auth/validate_sasl_mechanism.js @@ -0,0 +1,23 @@ +// Test for invalid sasl auth mechanisms + +(function() { +'use strict'; + +function waitFailedToStart(pid, exitCode) { + assert.soon(function() { + const res = checkProgram(pid); + if (res.alive) { + return false; + } + + return res.exitCode == exitCode; + }, `Failed to wait for ${pid} to die with exit code ${exitCode}`, 30 * 1000); +} + +const m = MongoRunner.runMongod({ + setParameter: "authenticationMechanisms=SCRAM-SHA-1,foo", + waitForConnect: false, +}); + +waitFailedToStart(m.pid, 2); +})(); diff --git a/src/mongo/db/auth/sasl_mechanism_registry.cpp b/src/mongo/db/auth/sasl_mechanism_registry.cpp index bfe479143d3..090e5cf08d6 100644 --- a/src/mongo/db/auth/sasl_mechanism_registry.cpp +++ b/src/mongo/db/auth/sasl_mechanism_registry.cpp @@ -33,11 +33,13 @@ #include "mongo/db/auth/sasl_mechanism_registry.h" #include "mongo/base/init.h" +#include "mongo/client/authenticate.h" #include "mongo/db/auth/sasl_options.h" #include "mongo/db/auth/user.h" #include "mongo/util/icu.h" #include "mongo/util/log.h" #include "mongo/util/net/socket_utils.h" +#include "mongo/util/quick_exit.h" #include "mongo/util/scopeguard.h" #include "mongo/util/sequence_util.h" @@ -144,6 +146,26 @@ bool SASLServerMechanismRegistry::_mechanismSupportedByConfig(StringData mechNam return sequenceContains(_enabledMechanisms, mechName); } +void appendMechs(const std::vector>& mechs, + std::vector* pNames) { + std::transform(mechs.cbegin(), + mechs.cend(), + std::back_inserter(*pNames), + [](const std::unique_ptr& factory) { + return factory->mechanismName().toString(); + }); +} + +std::vector SASLServerMechanismRegistry::getMechanismNames() const { + std::vector names; + names.reserve(_externalMechs.size() + _internalMechs.size()); + + appendMechs(_externalMechs, &names); + appendMechs(_internalMechs, &names); + + return names; +} + namespace { ServiceContext::ConstructorActionRegisterer SASLServerMechanismRegistryInitializer{ "CreateSASLServerMechanismRegistry", {"EndStartupOptionStorage"}, [](ServiceContext* service) { @@ -151,6 +173,27 @@ ServiceContext::ConstructorActionRegisterer SASLServerMechanismRegistryInitializ std::make_unique( saslGlobalParams.authenticationMechanisms)); }}; + +ServiceContext::ConstructorActionRegisterer SASLServerMechanismRegistryValidationInitializer{ + "ValidateSASLServerMechanismRegistry", [](ServiceContext* service) { + auto supportedMechanisms = SASLServerMechanismRegistry::get(service).getMechanismNames(); + + // Manually include MONGODB-X509 since there is no factory for it since it not a SASL + // mechanism + supportedMechanisms.push_back(auth::kMechanismMongoX509.toString()); + + // Error if the user tries to use a SASL mechanism that does not exist + for (const auto& mech : saslGlobalParams.authenticationMechanisms) { + auto it = std::find(supportedMechanisms.cbegin(), supportedMechanisms.cend(), mech); + if (it == supportedMechanisms.end()) { + error() << "SASL Mechanism '" << mech << "' is not supported"; + + // Quick Exit since we are in the middle of setting up ServiceContext + quickExit(EXIT_BADOPTIONS); + } + } + }}; + } // namespace } // namespace mongo diff --git a/src/mongo/db/auth/sasl_mechanism_registry.h b/src/mongo/db/auth/sasl_mechanism_registry.h index d9366eaaf59..7e9b8eee95a 100644 --- a/src/mongo/db/auth/sasl_mechanism_registry.h +++ b/src/mongo/db/auth/sasl_mechanism_registry.h @@ -357,6 +357,8 @@ public: return true; } + std::vector getMechanismNames() const; + private: using MechList = std::vector>; @@ -390,6 +392,7 @@ public: GlobalSASLMechanismRegisterer() { registerer.emplace(std::string(typeid(Factory).name()), std::vector{"CreateSASLServerMechanismRegistry"}, + std::vector{"ValidateSASLServerMechanismRegistry"}, [](ServiceContext* service) { SASLServerMechanismRegistry::get(service).registerFactory(); }); diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp index f14fce1404c..836fffd5133 100644 --- a/src/mongo/db/service_context.cpp +++ b/src/mongo/db/service_context.cpp @@ -382,6 +382,15 @@ ServiceContext::ConstructorActionRegisterer::ConstructorActionRegisterer( std::string name, std::vector prereqs, ConstructorAction constructor, + DestructorAction destructor) + : ConstructorActionRegisterer( + std::move(name), prereqs, {}, std::move(constructor), std::move(destructor)) {} + +ServiceContext::ConstructorActionRegisterer::ConstructorActionRegisterer( + std::string name, + std::vector prereqs, + std::vector dependents, + ConstructorAction constructor, DestructorAction destructor) { if (!destructor) destructor = [](ServiceContext*) {}; @@ -397,7 +406,8 @@ ServiceContext::ConstructorActionRegisterer::ConstructorActionRegisterer( registeredConstructorActions().erase(_iter); return Status::OK(); }, - std::move(prereqs)); + std::move(prereqs), + std::move(dependents)); } ServiceContext::UniqueServiceContext ServiceContext::make() { diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index e3af71deab5..7fd3383da0c 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -271,6 +271,23 @@ public: ConstructorAction constructor, DestructorAction destructor = {}); + /** + * This constructor registers a constructor and optional destructor with the given + * "name", a list of names of prerequisites, "prereqs", and a list of names of dependents, + * "dependents". + * + * The named constructor will run after all of its prereqs successfully complete, + * and the corresponding destructor, if provided, will run before any of its + * prerequisites execute. The dependents will run after this constructor and + * the corresponding destructor, if provided, will run after any of its + * dependents execute. + */ + ConstructorActionRegisterer(std::string name, + std::vector prereqs, + std::vector dependents, + ConstructorAction constructor, + DestructorAction destructor = {}); + private: using ConstructorActionListIterator = stdx::list::iterator; ConstructorActionListIterator _iter; -- cgit v1.2.1