summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2021-06-16 10:41:25 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-16 15:40:35 +0000
commitc73b1c09eb5ce2053577abac0a4ba360e3845de8 (patch)
tree90ebcc920053920129cd0c2d4e60d0ca4146f3a2 /src/mongo/db
parenta616859a60e6cbb40ab0b7ddbeed06e726bd40bc (diff)
downloadmongo-c73b1c09eb5ce2053577abac0a4ba360e3845de8.tar.gz
SERVER-55792 Verify credentials when clusterAuthMode is set via setParameter
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/SConscript24
-rw-r--r--src/mongo/db/auth/SConscript21
-rw-r--r--src/mongo/db/auth/auth_decorations.cpp19
-rw-r--r--src/mongo/db/auth/authorization_manager_global.cpp39
-rw-r--r--src/mongo/db/auth/cluster_auth_mode.cpp196
-rw-r--r--src/mongo/db/auth/cluster_auth_mode.h150
-rw-r--r--src/mongo/db/auth/sasl_scram_server_conversation.cpp25
-rw-r--r--src/mongo/db/auth/security_key.cpp14
-rw-r--r--src/mongo/db/auth/security_key.h4
-rw-r--r--src/mongo/db/auth/security_key_test.cpp5
-rw-r--r--src/mongo/db/commands/SConscript1
-rw-r--r--src/mongo/db/commands/authentication_commands.cpp47
-rw-r--r--src/mongo/db/initialize_server_security_state.cpp75
-rw-r--r--src/mongo/db/initialize_server_security_state.h41
-rw-r--r--src/mongo/db/mongod_main.cpp4
-rw-r--r--src/mongo/db/mongod_options.cpp5
-rw-r--r--src/mongo/db/server_options.h27
-rw-r--r--src/mongo/db/server_options_base.cpp10
-rw-r--r--src/mongo/db/server_options_server_helpers.cpp30
19 files changed, 494 insertions, 243 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index c30feb23528..b6036db8e53 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -306,6 +306,7 @@ env.Library(
'$BUILD_DIR/mongo/base',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/auth/cluster_auth_mode',
'$BUILD_DIR/mongo/util/options_parser/options_parser',
'server_options_core',
],
@@ -325,26 +326,8 @@ env.Clone().InjectModule("enterprise").Library(
'server_options',
'server_options_base',
],
-)
-
-# This library is linked into mongos and mongod only, not into the shell or any tools.
-env.Library(
- target="initialize_server_security_state",
- source=[
- "initialize_server_security_state.cpp",
- ],
- LIBDEPS=[
- "serverinit",
- ],
LIBDEPS_PRIVATE=[
- "$BUILD_DIR/mongo/client/authentication",
- "$BUILD_DIR/mongo/db/auth/auth",
- "$BUILD_DIR/mongo/db/auth/security_key",
- "$BUILD_DIR/mongo/rpc/metadata",
- "$BUILD_DIR/mongo/rpc/rpc",
- "$BUILD_DIR/mongo/util/net/ssl_manager",
- "$BUILD_DIR/mongo/util/net/ssl_parameters_auth",
- "auth/authorization_manager_global",
+ '$BUILD_DIR/mongo/db/auth/cluster_auth_mode',
],
)
@@ -384,6 +367,7 @@ env.Library(
'mongod_options_storage.idl',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/auth/cluster_auth_mode',
'$BUILD_DIR/mongo/db/repl/repl_settings',
'$BUILD_DIR/mongo/db/repl/replica_set_messages',
'$BUILD_DIR/mongo/db/storage/storage_options',
@@ -2097,7 +2081,6 @@ env.Library(
'index/index_access_methods',
'index/index_descriptor',
'index_builds_coordinator_mongod',
- 'initialize_server_security_state',
'initialize_snmp',
'introspect',
'keys_collection_client_direct',
@@ -2200,7 +2183,6 @@ env.Library(
'index/index_access_method_factory',
'index/index_access_methods',
'index_builds_coordinator_mongod',
- 'initialize_server_security_state',
'initialize_snmp',
'keys_collection_client_direct',
'kill_sessions',
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index f0e4da41fc7..6d1a9073014 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -33,6 +33,8 @@ env.Library(
'$BUILD_DIR/mongo/db/service_context',
],
LIBDEPS_PRIVATE=[
+ 'auth_options',
+ 'cluster_auth_mode',
'sasl_options',
],
)
@@ -131,6 +133,16 @@ env.Library(
)
env.Library(
+ target='cluster_auth_mode',
+ source=[
+ 'cluster_auth_mode.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ ],
+)
+
+env.Library(
target='auth_options',
source=[
"auth_options.idl",
@@ -266,7 +278,12 @@ env.Library(
'authorization_manager_global_parameters.idl',
],
LIBDEPS_PRIVATE=[
+ "$BUILD_DIR/mongo/client/authentication",
'$BUILD_DIR/mongo/idl/server_parameter',
+ "$BUILD_DIR/mongo/util/net/ssl_manager",
+ "$BUILD_DIR/mongo/util/net/ssl_parameters_auth",
+ 'cluster_auth_mode',
+ 'security_key'
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/server_options_core',
@@ -290,6 +307,7 @@ env.Library(
'$BUILD_DIR/mongo/util/icu',
'$BUILD_DIR/mongo/util/md5',
'auth',
+ 'cluster_auth_mode',
'sasl_options',
'security_file',
'user',
@@ -396,6 +414,9 @@ env.Library(
'sasl_options',
'user',
],
+ LIBDEPS_PRIVATE=[
+ 'cluster_auth_mode',
+ ],
)
env.Library(
diff --git a/src/mongo/db/auth/auth_decorations.cpp b/src/mongo/db/auth/auth_decorations.cpp
index 9dc6ccf868e..c4eb1af64af 100644
--- a/src/mongo/db/auth/auth_decorations.cpp
+++ b/src/mongo/db/auth/auth_decorations.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/auth/sasl_options.h"
#include "mongo/db/client.h"
#include "mongo/db/commands/authentication_commands.h"
@@ -56,6 +57,9 @@ struct DisabledAuthMechanisms {
const auto getDisabledAuthMechanisms = ServiceContext::declareDecoration<DisabledAuthMechanisms>();
+const auto getClusterAuthMode =
+ ServiceContext::declareDecoration<synchronized_value<ClusterAuthMode>>();
+
class AuthzClientObserver final : public ServiceContext::ClientObserver {
public:
void onCreateClient(Client* client) override {
@@ -133,6 +137,21 @@ void AuthorizationSession::set(Client* client,
authzSession = std::move(authorizationSession);
}
+ClusterAuthMode ClusterAuthMode::get(ServiceContext* svcCtx) {
+ return getClusterAuthMode(svcCtx).get();
+}
+
+ClusterAuthMode ClusterAuthMode::set(ServiceContext* svcCtx, const ClusterAuthMode& mode) {
+ auto sv = getClusterAuthMode(svcCtx).synchronize();
+ if (!sv->canTransitionTo(mode)) {
+ uasserted(5579202,
+ fmt::format("Illegal state transition for clusterAuthMode from '{}' to '{}'",
+ sv->toString(),
+ mode.toString()));
+ }
+ return std::exchange(*sv, mode);
+}
+
void disableX509Auth(ServiceContext* svcCtx) {
getDisabledAuthMechanisms(svcCtx).x509 = true;
}
diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp
index 9a7651bb91f..b7a21b94fa5 100644
--- a/src/mongo/db/auth/authorization_manager_global.cpp
+++ b/src/mongo/db/auth/authorization_manager_global.cpp
@@ -29,13 +29,19 @@
#include "mongo/platform/basic.h"
+#include "mongo/client/authenticate.h"
+#include "mongo/config.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global_parameters_gen.h"
#include "mongo/db/auth/authz_manager_external_state.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
+#include "mongo/db/auth/sasl_command_constants.h"
+#include "mongo/db/auth/security_key.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/server_options.h"
#include "mongo/db/service_context.h"
#include "mongo/util/assert_util.h"
+#include "mongo/util/net/ssl_manager.h"
namespace mongo {
namespace {
@@ -44,11 +50,40 @@ ServiceContext::ConstructorActionRegisterer createAuthorizationManager(
"CreateAuthorizationManager",
{"OIDGeneration", "EndStartupOptionStorage"},
[](ServiceContext* service) {
+ // Officially set the ClusterAuthMode for this ServiceContext
+ ClusterAuthMode::set(service, serverGlobalParams.startupClusterAuthMode);
+
+ const auto clusterAuthMode = serverGlobalParams.startupClusterAuthMode;
+ const auto authIsEnabled =
+ serverGlobalParams.authState == ServerGlobalParams::AuthState::kEnabled;
+
auto authzManager = AuthorizationManager::create(service);
- authzManager->setAuthEnabled(serverGlobalParams.authState ==
- ServerGlobalParams::AuthState::kEnabled);
+ authzManager->setAuthEnabled(authIsEnabled);
authzManager->setShouldValidateAuthSchemaOnStartup(gStartupAuthSchemaValidation);
+
+ // Auto-enable auth unless we are in mixed auth/no-auth or clusterAuthMode was not provided.
+ // clusterAuthMode defaults to "keyFile" if a --keyFile parameter is provided.
+ if (clusterAuthMode.isDefined() && !serverGlobalParams.transitionToAuth) {
+ authzManager->setAuthEnabled(true);
+ }
AuthorizationManager::set(service, std::move(authzManager));
+
+ if (clusterAuthMode.allowsKeyFile()) {
+ // Load up the keys if we allow key files authentication.
+ const auto gotKeys = setUpSecurityKey(serverGlobalParams.keyFile, clusterAuthMode);
+ uassert(5579201, "Unable to acquire security key[s]", gotKeys);
+ }
+
+ if (clusterAuthMode.sendsX509()) {
+ // Send x509 authentication if we can.
+#ifdef MONGO_CONFIG_SSL
+ auth::setInternalUserAuthParams(auth::createInternalX509AuthDocument(
+ boost::optional<StringData>{SSLManagerCoordinator::get()
+ ->getSSLManager()
+ ->getSSLConfiguration()
+ .clientSubjectName.toString()}));
+#endif
+ }
});
} // namespace
diff --git a/src/mongo/db/auth/cluster_auth_mode.cpp b/src/mongo/db/auth/cluster_auth_mode.cpp
new file mode 100644
index 00000000000..6f8470981ab
--- /dev/null
+++ b/src/mongo/db/auth/cluster_auth_mode.cpp
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kAccessControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/cluster_auth_mode.h"
+
+#include "mongo/logv2/log.h"
+
+namespace mongo {
+namespace {
+constexpr auto kKeyFileStr = "keyFile"_sd;
+constexpr auto kSendKeyFileStr = "sendKeyFile"_sd;
+constexpr auto kSendX509Str = "sendX509"_sd;
+constexpr auto kX509Str = "x509"_sd;
+constexpr auto kUndefinedStr = "undefined"_sd;
+} // namespace
+
+StatusWith<ClusterAuthMode> ClusterAuthMode::parse(StringData strMode) {
+ if (strMode == kKeyFileStr) {
+ return ClusterAuthMode(Value::kKeyFile);
+ } else if (strMode == kSendKeyFileStr) {
+ return ClusterAuthMode(Value::kSendKeyFile);
+ } else if (strMode == kSendX509Str) {
+ return ClusterAuthMode(Value::kSendX509);
+ } else if (strMode == kX509Str) {
+ return ClusterAuthMode(Value::kX509);
+ } else {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "Invalid clusterAuthMode '" << strMode << "'");
+ }
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::isDefined() const {
+ switch (_value) {
+ case Value::kUndefined:
+ return false;
+ case Value::kX509:
+ case Value::kKeyFile:
+ case Value::kSendKeyFile:
+ case Value::kSendX509:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::canTransitionTo(const ClusterAuthMode& mode) const {
+ switch (_value) {
+ case Value::kUndefined:
+ return true;
+ case Value::kKeyFile:
+ return mode._value == Value::kSendKeyFile;
+ case Value::kSendKeyFile:
+ return mode._value == Value::kSendX509;
+ case Value::kSendX509:
+ return mode._value == Value::kX509;
+ case Value::kX509:
+ return false;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::keyFileOnly() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kSendKeyFile:
+ case Value::kSendX509:
+ case Value::kX509:
+ return false;
+ case Value::kKeyFile:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::allowsKeyFile() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kX509:
+ return false;
+ case Value::kKeyFile:
+ case Value::kSendKeyFile:
+ case Value::kSendX509:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::allowsX509() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kKeyFile:
+ return false;
+ case Value::kSendKeyFile:
+ case Value::kSendX509:
+ case Value::kX509:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::sendsKeyFile() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kSendX509:
+ case Value::kX509:
+ return false;
+ case Value::kKeyFile:
+ case Value::kSendKeyFile:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::sendsX509() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kKeyFile:
+ case Value::kSendKeyFile:
+ return false;
+ case Value::kSendX509:
+ case Value::kX509:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+bool ClusterAuthMode::x509Only() const {
+ switch (_value) {
+ case Value::kUndefined:
+ case Value::kKeyFile:
+ case Value::kSendKeyFile:
+ case Value::kSendX509:
+ return false;
+ case Value::kX509:
+ return true;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+StringData ClusterAuthMode::toString() const {
+ switch (_value) {
+ case Value::kUndefined:
+ return kUndefinedStr;
+ case Value::kKeyFile:
+ return kKeyFileStr;
+ case Value::kSendKeyFile:
+ return kSendKeyFileStr;
+ case Value::kSendX509:
+ return kSendX509Str;
+ case Value::kX509:
+ return kX509Str;
+ };
+
+ MONGO_UNREACHABLE;
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/cluster_auth_mode.h b/src/mongo/db/auth/cluster_auth_mode.h
new file mode 100644
index 00000000000..a46a0922071
--- /dev/null
+++ b/src/mongo/db/auth/cluster_auth_mode.h
@@ -0,0 +1,150 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/base/status_with.h"
+#include "mongo/base/string_data.h"
+
+namespace mongo {
+
+class ServiceContext;
+
+/**
+ * ClusterAuthMode is a thin wrapper around an enum for decorated storage and semantic utility.
+ */
+class ClusterAuthMode {
+ enum class Value {
+ kUndefined,
+ /**
+ * Authenticate using keyfile, accept only keyfiles
+ */
+ kKeyFile,
+
+ /**
+ * Authenticate using keyfile, accept both keyfiles and X.509
+ */
+ kSendKeyFile,
+
+ /**
+ * Authenticate using X.509, accept both keyfiles and X.509
+ */
+ kSendX509,
+
+ /**
+ * Authenticate using X.509, accept only X.509
+ */
+ kX509
+ };
+
+public:
+ /**
+ * Parse a string and return either a ClusterAuthMode or a not-okay Status.
+ */
+ static StatusWith<ClusterAuthMode> parse(StringData strMode);
+
+ /**
+ * Return a pre-constructed ClusterAuthMode for keyFile mode.
+ *
+ * This is used for implied-key file startup.
+ */
+ static ClusterAuthMode keyFile() {
+ return ClusterAuthMode(Value::kKeyFile);
+ }
+
+ /**
+ * Get the ClusterAuthMode associated with the given ServiceContext.
+ *
+ * This function is synchronized.
+ */
+ static ClusterAuthMode get(ServiceContext* svcCtx);
+
+ /**
+ * Set the ClusterAuthMode associated with a ServiceContext and return the previous mode.
+ *
+ * This function is synchronized.
+ */
+ static ClusterAuthMode set(ServiceContext* svcCtx, const ClusterAuthMode& mode);
+
+ ClusterAuthMode() = default;
+ ~ClusterAuthMode() = default;
+
+ /**
+ * Returns true if this mode is allowed to transition to the other mode.
+ */
+ bool canTransitionTo(const ClusterAuthMode& mode) const;
+
+ /**
+ * Returns true if this mode is defined.
+ */
+ bool isDefined() const;
+
+ /**
+ * Returns true if this mode allows x509 authentication as a server.
+ */
+ bool allowsX509() const;
+
+ /**
+ * Returns true if this mode allows key file authentication as a server.
+ */
+ bool allowsKeyFile() const;
+
+ /**
+ * Returns true if this mode sends x509 authentication as a client.
+ */
+ bool sendsX509() const;
+
+ /**
+ * Returns true if this mode sends key file authentication as a client.
+ */
+ bool sendsKeyFile() const;
+
+ /**
+ * Returns true if this mode only sends and receives x509 authentication.
+ */
+ bool x509Only() const;
+
+ /**
+ * Returns true if this mode only sends and receives keyfile authentication.
+ */
+ bool keyFileOnly() const;
+
+ /**
+ * Returns a constant string representing this mode.
+ */
+ StringData toString() const;
+
+private:
+ // For now, we can require that static functions are used to make modes.
+ ClusterAuthMode(Value value) : _value(value) {}
+
+ Value _value = Value::kUndefined;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/sasl_scram_server_conversation.cpp b/src/mongo/db/auth/sasl_scram_server_conversation.cpp
index d92b4711c01..8273de3fbba 100644
--- a/src/mongo/db/auth/sasl_scram_server_conversation.cpp
+++ b/src/mongo/db/auth/sasl_scram_server_conversation.cpp
@@ -39,6 +39,7 @@
#include "mongo/base/string_data.h"
#include "mongo/crypto/mechanism_scram.h"
#include "mongo/crypto/sha1_block.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/auth/sasl_command_constants.h"
#include "mongo/db/auth/sasl_mechanism_policies.h"
#include "mongo/db/auth/sasl_mechanism_registry.h"
@@ -177,14 +178,26 @@ StatusWith<std::tuple<bool, std::string>> SaslSCRAMServerMechanism<Policy>::_fir
UserName user(ServerMechanismBase::ServerMechanismBase::_principalName,
ServerMechanismBase::getAuthenticationDatabase());
+ const auto isInternalUser = (user == internalSecurity.user->getName());
+ const auto clusterAuthMode = ClusterAuthMode::get(opCtx->getServiceContext());
+
// SERVER-16534, some mechanisms must be enabled for authenticating the internal user, so that
// cluster members may communicate with each other. Hence ignore disabled auth mechanism
// for the internal user.
- if (Policy::isInternalAuthMech() &&
- !sequenceContains(saslGlobalParams.authenticationMechanisms, Policy::getName()) &&
- user != internalSecurity.user->getName()) {
- return Status(ErrorCodes::BadValue,
- str::stream() << Policy::getName() << " authentication is disabled");
+ if (Policy::isInternalAuthMech()) {
+ if (isInternalUser) {
+ if (!clusterAuthMode.allowsKeyFile()) {
+ // We can no longer accept keyfiles.
+ return Status(ErrorCodes::BadValue,
+ str::stream() << Policy::getName()
+ << " is disallowed for cluster authentication");
+ }
+ } else {
+ if (!sequenceContains(saslGlobalParams.authenticationMechanisms, Policy::getName())) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << Policy::getName() << " authentication is disabled");
+ }
+ }
}
// The authentication database is also the source database for the user.
@@ -204,7 +217,7 @@ StatusWith<std::tuple<bool, std::string>> SaslSCRAMServerMechanism<Policy>::_fir
if (!scramCredentials.isValid()) {
// Check for authentication attempts of the __system user on
// systems started without a keyfile.
- if (userName == internalSecurity.user->getName()) {
+ if (isInternalUser) {
return Status(ErrorCodes::AuthenticationFailed,
"It is not possible to authenticate as the __system user "
"on servers started without a --keyFile parameter");
diff --git a/src/mongo/db/auth/security_key.cpp b/src/mongo/db/auth/security_key.cpp
index a9b012543fe..c09075d4f31 100644
--- a/src/mongo/db/auth/security_key.cpp
+++ b/src/mongo/db/auth/security_key.cpp
@@ -34,21 +34,15 @@
#include "mongo/db/auth/security_key.h"
#include <string>
-#include <sys/stat.h>
#include <vector>
#include "mongo/base/status_with.h"
-#include "mongo/client/authenticate.h"
+#include "mongo/client/internal_auth.h"
#include "mongo/crypto/mechanism_scram.h"
#include "mongo/crypto/sha1_block.h"
#include "mongo/crypto/sha256_block.h"
-#include "mongo/db/auth/action_set.h"
-#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_manager.h"
-#include "mongo/db/auth/privilege.h"
-#include "mongo/db/auth/sasl_command_constants.h"
#include "mongo/db/auth/sasl_options.h"
-#include "mongo/db/auth/sasl_scram_server_conversation.h"
#include "mongo/db/auth/security_file.h"
#include "mongo/db/auth/user.h"
#include "mongo/db/server_options.h"
@@ -135,7 +129,7 @@ private:
using std::string;
-bool setUpSecurityKey(const string& filename) {
+bool setUpSecurityKey(const string& filename, ClusterAuthMode mode) {
auto swKeyStrings = mongo::readSecurityFile(filename);
if (!swKeyStrings.isOK()) {
LOGV2(20254, "Read security file failed", "error"_attr = swKeyStrings.getStatus());
@@ -171,9 +165,7 @@ bool setUpSecurityKey(const string& filename) {
internalSecurity.alternateCredentials = std::move(*credentials);
}
- int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
- if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_keyFile ||
- clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile) {
+ if (mode.sendsKeyFile()) {
auth::setInternalAuthKeys(keyStrings);
}
diff --git a/src/mongo/db/auth/security_key.h b/src/mongo/db/auth/security_key.h
index 02a87aa5b23..bf53276994f 100644
--- a/src/mongo/db/auth/security_key.h
+++ b/src/mongo/db/auth/security_key.h
@@ -31,6 +31,8 @@
#include <string>
+#include "mongo/db/auth/cluster_auth_mode.h"
+
namespace mongo {
template <class T>
class StatusWith;
@@ -42,6 +44,6 @@ class StatusWith;
* @param filename the file containing the key
* @return if the key was successfully stored
*/
-bool setUpSecurityKey(const std::string& filename);
+bool setUpSecurityKey(const std::string& filename, ClusterAuthMode mode);
} // namespace mongo
diff --git a/src/mongo/db/auth/security_key_test.cpp b/src/mongo/db/auth/security_key_test.cpp
index fc1787b5962..1902eb93335 100644
--- a/src/mongo/db/auth/security_key_test.cpp
+++ b/src/mongo/db/auth/security_key_test.cpp
@@ -33,6 +33,7 @@
#include "mongo/base/string_data.h"
#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/auth/security_file.h"
#include "mongo/db/auth/security_key.h"
#include "mongo/unittest/unittest.h"
@@ -164,9 +165,9 @@ TEST(SecurityKey, Test) {
TestFile file(testCase.fileContents, testCase.mode != TestCase::FailureMode::Permissions);
if (testCase.mode == TestCase::FailureMode::Success) {
- ASSERT_TRUE(setUpSecurityKey(file.path().string()));
+ ASSERT_TRUE(setUpSecurityKey(file.path().string(), ClusterAuthMode::keyFile()));
} else {
- ASSERT_FALSE(setUpSecurityKey(file.path().string()));
+ ASSERT_FALSE(setUpSecurityKey(file.path().string(), ClusterAuthMode::keyFile()));
}
}
}
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index 5b338058572..fe8996d0112 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -194,6 +194,7 @@ env.Library(
'$BUILD_DIR/mongo/db/auth/auth',
'$BUILD_DIR/mongo/db/auth/auth_options',
'$BUILD_DIR/mongo/db/auth/authentication_session',
+ '$BUILD_DIR/mongo/db/auth/cluster_auth_mode',
'$BUILD_DIR/mongo/db/commands',
'$BUILD_DIR/mongo/rpc/client_metadata',
'$BUILD_DIR/mongo/util/net/ssl_manager',
diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp
index 9edc8bcc4d7..ba920d46e20 100644
--- a/src/mongo/db/commands/authentication_commands.cpp
+++ b/src/mongo/db/commands/authentication_commands.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/auth/auth_options_gen.h"
#include "mongo/db/auth/authentication_session.h"
#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/security_key.h"
#include "mongo/db/auth/user_name.h"
@@ -269,6 +270,8 @@ void _authenticateX509(OperationContext* opCtx, AuthenticationSession* session)
return opCtx->getClient()->session()->getTags() & transport::Session::kInternalClient;
};
+ const auto clusterAuthMode = ClusterAuthMode::get(opCtx->getServiceContext());
+
auto authorizeExternalUser = [&] {
uassert(ErrorCodes::BadValue,
kX509AuthenticationDisabledMessage,
@@ -278,31 +281,25 @@ void _authenticateX509(OperationContext* opCtx, AuthenticationSession* session)
if (sslConfiguration->isClusterMember(clientName)) {
// Handle internal cluster member auth, only applies to server-server connections
- switch (serverGlobalParams.clusterAuthMode.load()) {
- case ServerGlobalParams::ClusterAuthMode_undefined:
- case ServerGlobalParams::ClusterAuthMode_keyFile: {
- uassert(ErrorCodes::AuthenticationFailed,
- "The provided certificate can only be used for cluster authentication, not "
- "client authentication. The current configuration does not allow x.509 "
- "cluster authentication, check the --clusterAuthMode flag",
- !gEnforceUserClusterSeparation);
-
- authorizeExternalUser();
- } break;
- case ServerGlobalParams::ClusterAuthMode_sendKeyFile:
- case ServerGlobalParams::ClusterAuthMode_sendX509:
- case ServerGlobalParams::ClusterAuthMode_x509: {
- if (!isInternalClient()) {
- LOGV2_WARNING(
- 20430,
- "Client isn't a mongod or mongos, but is connecting with a certificate "
- "with cluster membership");
- }
-
- session->setAsClusterMember();
- authorizationSession->grantInternalAuthorization(client);
- } break;
- };
+ if (!clusterAuthMode.allowsX509()) {
+ uassert(ErrorCodes::AuthenticationFailed,
+ "The provided certificate can only be used for cluster authentication, not "
+ "client authentication. The current configuration does not allow x.509 "
+ "cluster authentication, check the --clusterAuthMode flag",
+ !gEnforceUserClusterSeparation);
+
+ authorizeExternalUser();
+ } else {
+ if (!isInternalClient()) {
+ LOGV2_WARNING(
+ 20430,
+ "Client isn't a mongod or mongos, but is connecting with a certificate "
+ "with cluster membership");
+ }
+
+ session->setAsClusterMember();
+ authorizationSession->grantInternalAuthorization(client);
+ }
} else {
// Handle normal client authentication, only applies to client-server connections
authorizeExternalUser();
diff --git a/src/mongo/db/initialize_server_security_state.cpp b/src/mongo/db/initialize_server_security_state.cpp
deleted file mode 100644
index 46a08632239..00000000000
--- a/src/mongo/db/initialize_server_security_state.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/initialize_server_global_state.h"
-
-#include "mongo/client/authenticate.h"
-#include "mongo/config.h"
-#include "mongo/db/auth/authorization_manager.h"
-#include "mongo/db/auth/sasl_command_constants.h"
-#include "mongo/db/auth/security_key.h"
-#include "mongo/db/server_options.h"
-#include "mongo/util/net/ssl_manager.h"
-
-namespace mongo {
-
-bool initializeServerSecurityGlobalState(ServiceContext* service) {
-
- int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
- if (!serverGlobalParams.keyFile.empty() &&
- clusterAuthMode != ServerGlobalParams::ClusterAuthMode_x509) {
- if (!setUpSecurityKey(serverGlobalParams.keyFile)) {
- // error message printed in setUpPrivateKey
- return false;
- }
- }
-
- // Auto-enable auth unless we are in mixed auth/no-auth or clusterAuthMode was not provided.
- // clusterAuthMode defaults to "keyFile" if a --keyFile parameter is provided.
- if (clusterAuthMode != ServerGlobalParams::ClusterAuthMode_undefined &&
- !serverGlobalParams.transitionToAuth) {
- AuthorizationManager::get(service)->setAuthEnabled(true);
- }
-
-#ifdef MONGO_CONFIG_SSL
- if (clusterAuthMode == ServerGlobalParams::ClusterAuthMode_x509 ||
- clusterAuthMode == ServerGlobalParams::ClusterAuthMode_sendX509) {
- auth::setInternalUserAuthParams(auth::createInternalX509AuthDocument(
- boost::optional<StringData>{SSLManagerCoordinator::get()
- ->getSSLManager()
- ->getSSLConfiguration()
- .clientSubjectName.toString()}));
- }
-#endif
-
- return true;
-}
-} // namespace mongo
diff --git a/src/mongo/db/initialize_server_security_state.h b/src/mongo/db/initialize_server_security_state.h
deleted file mode 100644
index d6c4d18b08e..00000000000
--- a/src/mongo/db/initialize_server_security_state.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-namespace mongo {
-
-class ServiceContext;
-
-/**
- * Perform security initialization activity for mongod and mongos.
- */
-bool initializeServerSecurityGlobalState(ServiceContext* service);
-
-} // namespace mongo
diff --git a/src/mongo/db/mongod_main.cpp b/src/mongo/db/mongod_main.cpp
index e42e56c5f34..c14577624c5 100644
--- a/src/mongo/db/mongod_main.cpp
+++ b/src/mongo/db/mongod_main.cpp
@@ -88,7 +88,6 @@
#include "mongo/db/index_builds_coordinator_mongod.h"
#include "mongo/db/index_names.h"
#include "mongo/db/initialize_server_global_state.h"
-#include "mongo/db/initialize_server_security_state.h"
#include "mongo/db/initialize_snmp.h"
#include "mongo/db/introspect.h"
#include "mongo/db/json.h"
@@ -1468,9 +1467,6 @@ int mongod_main(int argc, char* argv[]) {
if (!initializeServerGlobalState(service))
quickExit(EXIT_FAILURE);
- if (!initializeServerSecurityGlobalState(service))
- quickExit(EXIT_FAILURE);
-
// There is no single-threaded guarantee beyond this point.
ThreadSafetyContext::getThreadSafetyContext()->allowMultiThreading();
diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp
index ee0bbd93040..881f83c1abc 100644
--- a/src/mongo/db/mongod_options.cpp
+++ b/src/mongo/db/mongod_options.cpp
@@ -41,6 +41,7 @@
#include "mongo/bson/json.h"
#include "mongo/bson/util/builder.h"
#include "mongo/config.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/cluster_auth_mode_option_gen.h"
#include "mongo/db/global_settings.h"
#include "mongo/db/keyfile_option_gen.h"
@@ -515,8 +516,8 @@ Status storeMongodOptions(const moe::Environment& params) {
if (!replSettings.getReplSetString().empty() &&
(params.count("security.authorization") &&
params["security.authorization"].as<std::string>() == "enabled") &&
- serverGlobalParams.clusterAuthMode.load() != ServerGlobalParams::ClusterAuthMode_x509 &&
- !params.count("security.keyFile")) {
+ !serverGlobalParams.startupClusterAuthMode.x509Only() &&
+ serverGlobalParams.keyFile.empty()) {
return Status(
ErrorCodes::BadValue,
str::stream()
diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h
index c14b522821e..7a5e3cd226f 100644
--- a/src/mongo/db/server_options.h
+++ b/src/mongo/db/server_options.h
@@ -29,6 +29,7 @@
#pragma once
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/jsobj.h"
#include "mongo/logv2/log_format.h"
#include "mongo/platform/atomic_word.h"
@@ -122,31 +123,9 @@ struct ServerGlobalParams {
AuthState authState = AuthState::kUndefined;
- bool transitionToAuth = false; // --transitionToAuth, mixed mode for rolling auth upgrade
- AtomicWord<int> clusterAuthMode; // --clusterAuthMode, the internal cluster auth mode
+ bool transitionToAuth = false; // --transitionToAuth, mixed mode for rolling auth upgrade
- enum ClusterAuthModes {
- ClusterAuthMode_undefined,
- /**
- * Authenticate using keyfile, accept only keyfiles
- */
- ClusterAuthMode_keyFile,
-
- /**
- * Authenticate using keyfile, accept both keyfiles and X.509
- */
- ClusterAuthMode_sendKeyFile,
-
- /**
- * Authenticate using X.509, accept both keyfiles and X.509
- */
- ClusterAuthMode_sendX509,
-
- /**
- * Authenticate using X.509, accept only X.509
- */
- ClusterAuthMode_x509
- };
+ ClusterAuthMode startupClusterAuthMode;
// for the YAML config, sharding._overrideShardIdentity. Can only be used when in
// queryableBackupMode.
diff --git a/src/mongo/db/server_options_base.cpp b/src/mongo/db/server_options_base.cpp
index 1cdda7e93d7..d8768dfcd02 100644
--- a/src/mongo/db/server_options_base.cpp
+++ b/src/mongo/db/server_options_base.cpp
@@ -30,6 +30,7 @@
#include "mongo/db/server_options_base.h"
#include "mongo/base/string_data.h"
+#include "mongo/db/auth/cluster_auth_mode.h"
#include "mongo/db/server_options_base_gen.h"
#include "mongo/db/server_options_general_gen.h"
#include "mongo/logv2/log_component.h"
@@ -108,14 +109,7 @@ Status validateSystemLogDestinationSetting(const std::string& value) {
}
Status validateSecurityClusterAuthModeSetting(const std::string& value) {
- // keyFile|sendKeyFile|sendX509|x509
- constexpr auto kKeyFile = "keyFile"_sd;
- constexpr auto kSendKeyFile = "sendKeyFile"_sd;
- constexpr auto kSendX509 = "sendX509"_sd;
- constexpr auto kX509 = "X509"_sd;
-
- if (!kKeyFile.equalCaseInsensitive(value) && !kSendKeyFile.equalCaseInsensitive(value) &&
- !kSendX509.equalCaseInsensitive(value) && !kX509.equalCaseInsensitive(value)) {
+ if (!ClusterAuthMode::parse(value).isOK()) {
return {ErrorCodes::BadValue,
"security.clusterAuthMode expects one of 'keyFile', 'sendKeyFile', 'sendX509', or "
"'X509'"};
diff --git a/src/mongo/db/server_options_server_helpers.cpp b/src/mongo/db/server_options_server_helpers.cpp
index 641ce12cca6..57f05b16ba4 100644
--- a/src/mongo/db/server_options_server_helpers.cpp
+++ b/src/mongo/db/server_options_server_helpers.cpp
@@ -316,24 +316,10 @@ Status storeServerOptions(const moe::Environment& params) {
}
if (params.count("security.clusterAuthMode")) {
- std::string clusterAuthMode = params["security.clusterAuthMode"].as<std::string>();
-
- if (clusterAuthMode == "keyFile") {
- serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_keyFile);
- } else if (clusterAuthMode == "sendKeyFile") {
- serverGlobalParams.clusterAuthMode.store(
- ServerGlobalParams::ClusterAuthMode_sendKeyFile);
- } else if (clusterAuthMode == "sendX509") {
- serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_sendX509);
- } else if (clusterAuthMode == "x509") {
- serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_x509);
- } else {
- return Status(ErrorCodes::BadValue,
- "unsupported value for clusterAuthMode " + clusterAuthMode);
- }
+ const auto modeStr = params["security.clusterAuthMode"].as<std::string>();
+ serverGlobalParams.startupClusterAuthMode =
+ uassertStatusOK(ClusterAuthMode::parse(modeStr));
serverGlobalParams.authState = ServerGlobalParams::AuthState::kEnabled;
- } else {
- serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_undefined);
}
if (params.count("net.maxIncomingConnections")) {
@@ -432,12 +418,14 @@ Status storeServerOptions(const moe::Environment& params) {
}
if (!params.count("security.clusterAuthMode") && params.count("security.keyFile")) {
- serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_keyFile);
+ serverGlobalParams.startupClusterAuthMode = ClusterAuthMode::keyFile();
}
- int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
+
+ const bool hasClusterAuthMode = serverGlobalParams.startupClusterAuthMode.isDefined();
if (serverGlobalParams.transitionToAuth &&
- (clusterAuthMode != ServerGlobalParams::ClusterAuthMode_keyFile &&
- clusterAuthMode != ServerGlobalParams::ClusterAuthMode_x509)) {
+ !(hasClusterAuthMode &&
+ (serverGlobalParams.startupClusterAuthMode.x509Only() ||
+ serverGlobalParams.startupClusterAuthMode.keyFileOnly()))) {
return Status(ErrorCodes::BadValue,
"--transitionToAuth must be used with keyFile or x509 authentication");
}