diff options
author | Ben Caimano <ben.caimano@10gen.com> | 2021-02-17 17:42:20 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-02-18 17:01:33 +0000 |
commit | 5a76da986da7166226cc3da2eed081bc5263bfe6 (patch) | |
tree | f0b99b3a5055f9d6d5484d9a0493ec41fc7e3ccf /src/mongo | |
parent | f35a8a1cf31e5589f27012cf6df05c0adfe0b978 (diff) | |
download | mongo-5a76da986da7166226cc3da2eed081bc5263bfe6.tar.gz |
SERVER-54136 Make the authenticate command respect enforceUserClusterSeparation
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/auth/auth_options.idl | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/authentication_commands.cpp | 74 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.idl | 8 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_integration_fixture.cpp | 7 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_integration_fixture.h | 2 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_integration_test.cpp | 7 | ||||
-rw-r--r-- | src/mongo/shell/shardingtest.js | 39 | ||||
-rw-r--r-- | src/mongo/util/net/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/util/net/network_interface_ssl_test.cpp | 8 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options_server.cpp | 7 |
12 files changed, 98 insertions, 64 deletions
diff --git a/src/mongo/db/auth/auth_options.idl b/src/mongo/db/auth/auth_options.idl index 488e311ee75..a0d5139938a 100644 --- a/src/mongo/db/auth/auth_options.idl +++ b/src/mongo/db/auth/auth_options.idl @@ -42,3 +42,9 @@ server_parameters: cpp_vartype: bool cpp_varname: roleGraphInvalidationIsFatal test_only: true + enforceUserClusterSeparation: + description: "Prevents creation of users whose names would be interpreted as cluster members" + set_at: startup + cpp_varname: "gEnforceUserClusterSeparation" + cpp_vartype: bool + default: true diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index a95cdedef92..ee9aeb89c8f 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -201,6 +201,7 @@ env.Library( LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/bson/mutable/mutable_bson', '$BUILD_DIR/mongo/db/auth/auth', + '$BUILD_DIR/mongo/db/auth/auth_options', '$BUILD_DIR/mongo/db/auth/authentication_session', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/rpc/client_metadata', @@ -477,6 +478,7 @@ env.Library( '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/client/clientdriver_minimal', '$BUILD_DIR/mongo/db/auth/auth', + '$BUILD_DIR/mongo/db/auth/auth_options', '$BUILD_DIR/mongo/db/auth/authprivilege', '$BUILD_DIR/mongo/db/auth/builtin_roles', '$BUILD_DIR/mongo/db/auth/sasl_options', diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index 2ed31e74055..0f5b5b7a546 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -43,6 +43,7 @@ #include "mongo/client/authenticate.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/config.h" +#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/privilege.h" @@ -52,6 +53,7 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/authentication_commands_gen.h" #include "mongo/db/commands/test_commands_enabled.h" +#include "mongo/db/commands/user_management_commands_gen.h" #include "mongo/db/operation_context.h" #include "mongo/logv2/log.h" #include "mongo/platform/random.h" @@ -223,10 +225,6 @@ void _authenticateX509(OperationContext* opCtx, AuthenticationSession* session) "SSL support is required for the MONGODB-X509 mechanism.", opCtx->getClient()->session()->getSSLManager()); - uassert(ErrorCodes::ProtocolError, - "X.509 authentication must always use the $external database.", - user.getDB() == "$external"); - AuthorizationSession* authorizationSession = AuthorizationSession::get(client); auto sslConfiguration = opCtx->getClient()->session()->getSSLConfiguration(); @@ -235,39 +233,51 @@ void _authenticateX509(OperationContext* opCtx, AuthenticationSession* session) "Unable to verify x.509 certificate, as no CA has been provided.", sslConfiguration->hasCA); - // Handle internal cluster member auth, only applies to server-server connections - if (sslConfiguration->isClusterMember(clientName)) { - int clusterAuthMode = serverGlobalParams.clusterAuthMode.load(); - - 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", - clusterAuthMode != ServerGlobalParams::ClusterAuthMode_undefined && - clusterAuthMode != ServerGlobalParams::ClusterAuthMode_keyFile); - - if (auto clientMetadata = ClientMetadata::get(opCtx->getClient())) { - auto clientMetadataDoc = clientMetadata->getDocument(); - auto driverName = clientMetadataDoc.getObjectField("driver"_sd) - .getField("name"_sd) - .checkAndGetStringData(); - if (!clientMetadata->getApplicationName().empty() || - (driverName != "MongoDB Internal Client" && driverName != "NetworkInterfaceTL")) { - LOGV2_WARNING(20430, - "Client isn't a mongod or mongos, but is connecting with a " - "certificate with cluster membership"); - } - } + uassert(ErrorCodes::ProtocolError, + "X.509 authentication must always use the $external database.", + user.getDB() == kExternalDB); - session->setAsClusterMember(); - authorizationSession->grantInternalAuthorization(client); - } else { - // Handle normal client authentication, only applies to client-server connections + auto isInternalClient = [&]() -> bool { + return opCtx->getClient()->session()->getTags() & transport::Session::kInternalClient; + }; + + auto authorizeExternalUser = [&] { uassert(ErrorCodes::BadValue, kX509AuthenticationDisabledMessage, !isX509AuthDisabled(opCtx->getServiceContext())); uassertStatusOK(authorizationSession->addAndAuthorizeUser(opCtx, user)); + }; + + 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; + }; + } else { + // Handle normal client authentication, only applies to client-server connections + authorizeExternalUser(); } } #endif // MONGO_CONFIG_SSL diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 5462ae4ccb0..3336a1787b3 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -46,6 +46,7 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/address_restriction.h" +#include "mongo/db/auth/auth_options_gen.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege_parser.h" diff --git a/src/mongo/db/commands/user_management_commands.idl b/src/mongo/db/commands/user_management_commands.idl index d4dec18cb61..6c7b47ebf44 100644 --- a/src/mongo/db/commands/user_management_commands.idl +++ b/src/mongo/db/commands/user_management_commands.idl @@ -34,14 +34,6 @@ imports: - "mongo/db/auth/address_restriction.idl" - "mongo/db/auth/user_management_commands_parser.idl" -server_parameters: - enforceUserClusterSeparation: - description: "Prevents creation of users whose names would be interpreted as cluster members" - set_at: startup - cpp_varname: "gEnforceUserClusterSeparation" - cpp_vartype: bool - default: true - structs: dropAllUsersFromDatabaseReply: description: "Response for dropAllUsersFromDatabase command" diff --git a/src/mongo/executor/network_interface_integration_fixture.cpp b/src/mongo/executor/network_interface_integration_fixture.cpp index 62e452e8c69..c3401173cc1 100644 --- a/src/mongo/executor/network_interface_integration_fixture.cpp +++ b/src/mongo/executor/network_interface_integration_fixture.cpp @@ -34,6 +34,7 @@ #include <memory> #include "mongo/client/connection_string.h" +#include "mongo/db/wire_version.h" #include "mongo/executor/network_interface_factory.h" #include "mongo/executor/network_interface_integration_fixture.h" #include "mongo/executor/remote_command_response.h" @@ -91,6 +92,12 @@ PseudoRandom* NetworkInterfaceIntegrationFixture::getRandomNumberGenerator() { return _rng; } +void NetworkInterfaceIntegrationFixture::resetIsInternalClient(bool isInternalClient) { + WireSpec::Specification newSpec = *WireSpec::instance().get(); + newSpec.isInternalClient = isInternalClient; + WireSpec::instance().reset(std::move(newSpec)); +} + void NetworkInterfaceIntegrationFixture::startCommand(const TaskExecutor::CallbackHandle& cbHandle, RemoteCommandRequest& request, StartCommandCB onFinish) { diff --git a/src/mongo/executor/network_interface_integration_fixture.h b/src/mongo/executor/network_interface_integration_fixture.h index 226bce34a5c..3fd1e58413d 100644 --- a/src/mongo/executor/network_interface_integration_fixture.h +++ b/src/mongo/executor/network_interface_integration_fixture.h @@ -75,6 +75,8 @@ public: void setRandomNumberGenerator(PseudoRandom* generator); + void resetIsInternalClient(bool isInternalClient); + PseudoRandom* getRandomNumberGenerator(); void startCommand(const TaskExecutor::CallbackHandle& cbHandle, diff --git a/src/mongo/executor/network_interface_integration_test.cpp b/src/mongo/executor/network_interface_integration_test.cpp index 2496454d7c0..c5b23cd8a15 100644 --- a/src/mongo/executor/network_interface_integration_test.cpp +++ b/src/mongo/executor/network_interface_integration_test.cpp @@ -37,7 +37,6 @@ #include "mongo/base/status_with.h" #include "mongo/client/connection_string.h" -#include "mongo/db/wire_version.h" #include "mongo/executor/connection_pool_stats.h" #include "mongo/executor/network_connection_hook.h" #include "mongo/executor/network_interface_integration_fixture.h" @@ -151,12 +150,6 @@ public: constexpr static Milliseconds kNoTimeout = RemoteCommandRequest::kNoTimeout; constexpr static Milliseconds kMaxWait = Milliseconds(Minutes(1)); - void resetIsInternalClient(bool isInternalClient) { - WireSpec::Specification newSpec = *WireSpec::instance().get(); - newSpec.isInternalClient = isInternalClient; - WireSpec::instance().reset(std::move(newSpec)); - } - void assertNumOps(uint64_t canceled, uint64_t timedOut, uint64_t failed, uint64_t succeeded) { auto counters = net().getCounters(); ASSERT_EQ(canceled, counters.canceled); diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js index 2087653e897..d19ed6bdad9 100644 --- a/src/mongo/shell/shardingtest.js +++ b/src/mongo/shell/shardingtest.js @@ -393,6 +393,27 @@ var ShardingTest = function(params) { } }; + this.stopAllConfigServers = function(opts) { + if (this.configRS) { + this.configRS.stopSet(undefined, undefined, opts); + } else { + // Old style config triplet + for (var i = 0; i < this._configServers.length; i++) { + this.stopConfigServer(i, opts); + } + } + }; + + this.stopAllShards = function(opts) { + for (var i = 0; i < this._connections.length; i++) { + if (this._rs[i]) { + this._rs[i].test.stopSet(15, undefined, opts); + } else { + this.stopMongod(i, opts); + } + } + }; + this.stopAllMongos = function(opts) { for (var i = 0; i < this._mongos.length; i++) { this.stopMongos(i, opts); @@ -415,25 +436,11 @@ var ShardingTest = function(params) { this.stopAllMongos(opts); let startTime = new Date(); // Measure the execution time of shutting down shards. - for (var i = 0; i < this._connections.length; i++) { - if (this._rs[i]) { - this._rs[i].test.stopSet(15, undefined, opts); - } else { - this.stopMongod(i, opts); - } - } + this.stopAllShards(opts); print("ShardingTest stopped all shards, took " + (new Date() - startTime) + "ms for " + this._connections.length + " shards."); - if (this.configRS) { - this.configRS.stopSet(undefined, undefined, opts); - } else { - // Old style config triplet - for (var i = 0; i < this._configServers.length; i++) { - this.stopConfigServer(i, opts); - } - } - + this.stopAllConfigServers(opts); if (!opts.noCleanData) { print("ShardingTest stop deleting all dbpaths"); for (var i = 0; i < _alldbpaths.length; i++) { diff --git a/src/mongo/util/net/SConscript b/src/mongo/util/net/SConscript index 1b027d1fe86..45deefd544c 100644 --- a/src/mongo/util/net/SConscript +++ b/src/mongo/util/net/SConscript @@ -68,6 +68,7 @@ env.Library( 'ssl_options', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/auth/auth_options', '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/util/options_parser/options_parser', ] diff --git a/src/mongo/util/net/network_interface_ssl_test.cpp b/src/mongo/util/net/network_interface_ssl_test.cpp index afe6eeb6b18..2fe10c23884 100644 --- a/src/mongo/util/net/network_interface_ssl_test.cpp +++ b/src/mongo/util/net/network_interface_ssl_test.cpp @@ -54,6 +54,8 @@ std::string loadFile(const std::string& name) { class NetworkInterfaceSSLFixture : public NetworkInterfaceIntegrationFixture { public: void setUp() final { + resetIsInternalClient(true); + NetworkInterfaceIntegrationFixture::setUp(); // Setup an internal user so that we can use it for external auth UserHandle user(User(UserName("__system", "local"))); @@ -79,6 +81,11 @@ public: createNet(nullptr, std::move(options)); net().startup(); } + + void tearDown() override { + NetworkInterfaceIntegrationFixture::tearDown(); + resetIsInternalClient(false); + } }; TEST_F(NetworkInterfaceSSLFixture, Ping) { @@ -86,7 +93,6 @@ TEST_F(NetworkInterfaceSSLFixture, Ping) { "admin", BSON("ping" << 1), RemoteCommandRequest::kNoTimeout, transport::kEnableSSL); } - } // namespace } // namespace executor } // namespace mongo diff --git a/src/mongo/util/net/ssl_options_server.cpp b/src/mongo/util/net/ssl_options_server.cpp index 0b0f0b4e955..809befe82d8 100644 --- a/src/mongo/util/net/ssl_options_server.cpp +++ b/src/mongo/util/net/ssl_options_server.cpp @@ -37,6 +37,7 @@ #include "mongo/base/status.h" #include "mongo/config.h" +#include "mongo/db/auth/auth_options_gen.h" #include "mongo/db/server_options.h" #include "mongo/logv2/log.h" #include "mongo/util/options_parser/startup_option_init.h" @@ -232,6 +233,12 @@ MONGO_STARTUP_OPTIONS_POST(SSLServerOptions)(InitializerContext*) { if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_disabled) { uasserted(ErrorCodes::BadValue, "need to enable TLS via the tlsMode flag"); } + + if (!gEnforceUserClusterSeparation) { + uasserted(ErrorCodes::BadValue, + "cannot have have x.509 cluster authentication while not enforcing user " + "cluster separation"); + } } if (sslGlobalParams.sslMode.load() == SSLParams::SSLMode_allowSSL) { |