diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/auth | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/db/auth')
| -rw-r--r-- | src/mongo/db/auth/SConscript | 27 | ||||
| -rw-r--r-- | src/mongo/db/auth/action_type.idl | 19 | ||||
| -rw-r--r-- | src/mongo/db/auth/auth_name.cpp | 9 | ||||
| -rw-r--r-- | src/mongo/db/auth/auth_name.h | 2 | ||||
| -rw-r--r-- | src/mongo/db/auth/auth_op_observer.h | 4 | ||||
| -rw-r--r-- | src/mongo/db/auth/authentication_session.cpp | 50 | ||||
| -rw-r--r-- | src/mongo/db/auth/authentication_session.h | 6 | ||||
| -rw-r--r-- | src/mongo/db/auth/authorization_manager_impl.cpp | 8 | ||||
| -rw-r--r-- | src/mongo/db/auth/authorization_session_impl.cpp | 14 | ||||
| -rw-r--r-- | src/mongo/db/auth/authorization_session_test.cpp | 117 | ||||
| -rw-r--r-- | src/mongo/db/auth/authorization_session_test_fixture.cpp | 88 | ||||
| -rw-r--r-- | src/mongo/db/auth/authorization_session_test_fixture.h | 87 | ||||
| -rw-r--r-- | src/mongo/db/auth/builtin_roles.cpp | 42 | ||||
| -rw-r--r-- | src/mongo/db/auth/builtin_roles_test.cpp | 1 | ||||
| -rw-r--r-- | src/mongo/db/auth/resource_pattern.h | 4 | ||||
| -rw-r--r-- | src/mongo/db/auth/sasl_commands.h | 2 | ||||
| -rw-r--r-- | src/mongo/db/auth/sasl_mechanism_registry.h | 10 | ||||
| -rw-r--r-- | src/mongo/db/auth/user.cpp | 6 |
18 files changed, 156 insertions, 340 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index b8639a62846..57af14b709d 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -82,7 +82,7 @@ env.Library( '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/catalog/collection_options', - '$BUILD_DIR/mongo/db/index/index_access_method', + '$BUILD_DIR/mongo/db/index/index_descriptor', '$BUILD_DIR/mongo/db/op_observer', '$BUILD_DIR/mongo/db/op_observer_util', '$BUILD_DIR/mongo/db/repl/oplog_entry', @@ -189,9 +189,9 @@ env.Library( '$BUILD_DIR/mongo/base/secure_allocator', '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/curop', '$BUILD_DIR/mongo/db/global_settings', '$BUILD_DIR/mongo/db/namespace_string', - '$BUILD_DIR/mongo/db/query/query_stats/query_stats', '$BUILD_DIR/mongo/idl/feature_flag', '$BUILD_DIR/mongo/util/concurrency/thread_pool', '$BUILD_DIR/mongo/util/icu', @@ -514,7 +514,7 @@ env.Library( source=[ 'ldap_operation_stats.cpp', 'ldap_cumulative_operation_stats.cpp', - 'user_cache_acquisition_stats.cpp', + 'user_cache_acquisition_stats.cpp' ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', @@ -522,22 +522,6 @@ env.Library( ], ) -env.Library( - target='authorization_session_test_fixture', - source=[ - 'authorization_session_for_test.cpp', - 'authorization_session_test_fixture.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/service_context_d_test_fixture', - '$BUILD_DIR/mongo/transport/transport_layer_mock', - 'auth', - 'auth_impl_internal', - 'authentication_restriction', - 'authmocks', - ], -) - env.CppUnitTest( target='db_auth_test', source=[ @@ -547,6 +531,7 @@ env.CppUnitTest( 'authorization_contract_test.cpp', 'auth_op_observer_test.cpp', 'authorization_manager_test.cpp', + 'authorization_session_for_test.cpp', 'authorization_session_test.cpp', 'builtin_roles_test.cpp', 'privilege_parser_test.cpp', @@ -569,12 +554,14 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/service_context_d_test_fixture', '$BUILD_DIR/mongo/db/service_context_test_fixture', '$BUILD_DIR/mongo/transport/transport_layer_common', + '$BUILD_DIR/mongo/transport/transport_layer_mock', '$BUILD_DIR/mongo/util/net/network', 'address_restriction', + 'auth', + 'auth_impl_internal', 'auth_op_observer', 'authentication_restriction', 'authmocks', - 'authorization_session_test_fixture', 'saslauth', 'security_file', 'security_key', diff --git a/src/mongo/db/auth/action_type.idl b/src/mongo/db/auth/action_type.idl index 2c09bfca837..1d83378f275 100644 --- a/src/mongo/db/auth/action_type.idl +++ b/src/mongo/db/auth/action_type.idl @@ -45,7 +45,6 @@ enums: values: addShard : "addShard" advanceClusterTime : "advanceClusterTime" - allCollectionStats: "allCollectionStats" anyAction : "anyAction" # Special ActionType that represents *all* actions appendOplogNote : "appendOplogNote" applicationMessage : "applicationMessage" @@ -77,7 +76,6 @@ enums: createDatabase : "createDatabase" # ID only createIndex : "createIndex" # ID only createRole : "createRole" - createSearchIndexes : "createSearchIndexes" createUser : "createUser" dbCheck : "dbCheck" dbHash : "dbHash" @@ -88,7 +86,6 @@ enums: dropConnections : "dropConnections" dropDatabase : "dropDatabase" dropIndex : "dropIndex" - dropSearchIndex : "dropSearchIndex" dropRole : "dropRole" dropUser : "dropUser" emptycapped : "emptycapped" @@ -99,7 +96,6 @@ enums: flushRouterConfig : "flushRouterConfig" forceUUID : "forceUUID" fsync : "fsync" - fsyncUnlock: "fsyncUnlock" getClusterParameter: "getClusterParameter" getDatabaseVersion : "getDatabaseVersion" getDefaultRWConcern : "getDefaultRWConcern" @@ -129,7 +125,6 @@ enums: listCursors : "listCursors" listDatabases : "listDatabases" listIndexes : "listIndexes" - listSearchIndexes : "listSearchIndexes" listSessions : "listSessions" listShards : "listShards" logRotate : "logRotate" @@ -140,8 +135,6 @@ enums: planCacheIndexFilter : "planCacheIndexFilter" # view/update index filters planCacheRead : "planCacheRead" # view contents of plan cache planCacheWrite : "planCacheWrite" # clear cache, drop cache entry, pin/unpin/shun plans - queryStatsRead: "queryStatsRead" # view untransformed contents of queryStats store - queryStatsReadTransformed: "queryStatsReadTransformed" # view transformed contents of queryStats store refineCollectionShardKey : "refineCollectionShardKey" reIndex : "reIndex" remove : "remove" @@ -170,11 +163,10 @@ enums: setClusterParameter: "setClusterParameter" setDefaultRWConcern : "setDefaultRWConcern" setFeatureCompatibilityVersion : "setFeatureCompatibilityVersion" - setFreeMonitoring : "setFreeMonitoring" # Removed (backwards compatibility) + setFreeMonitoring : "setFreeMonitoring" setParameter : "setParameter" setUserWriteBlockMode: "setUserWriteBlockMode" shardCollection : "shardCollection" # ID only - shardedDataDistribution : "shardedDataDistribution" shardingState : "shardingState" shutdown : "shutdown" splitChunk : "splitChunk" @@ -188,7 +180,6 @@ enums: useUUID : "useUUID" update : "update" updateRole : "updateRole" # ID only - updateSearchIndex : "updateSearchIndex" updateUser : "updateUser" # ID only validate : "validate" viewRole : "viewRole" @@ -236,13 +227,11 @@ enums: - convertToCapped - createCollection - createIndex - - createSearchIndexes - dbCheck - dbHash - dbStats - dropCollection - dropIndex - - dropSearchIndex - exportCollection - find - importCollection @@ -251,14 +240,12 @@ enums: - killCursors - listCollections - listIndexes - - listSearchIndexes - planCacheRead - reIndex - remove - renameCollection - renameCollectionSameDB - update - - updateSearchIndex - validate # resource: { db: 'exact', collection: '' } @@ -278,13 +265,11 @@ enums: - convertToCapped - createCollection - createIndex - - createSearchIndexes - dbCheck - dbHash - dbStats - dropCollection - dropIndex - - dropSearchIndex - exportCollection - find - importCollection @@ -293,14 +278,12 @@ enums: - killCursors - listCollections - listIndexes - - listSearchIndexes - planCacheRead - reIndex - remove - renameCollection - renameCollectionSameDB - update - - updateSearchIndex - validate # Actions specific to the database match types. diff --git a/src/mongo/db/auth/auth_name.cpp b/src/mongo/db/auth/auth_name.cpp index 2c091c0f53e..4b8116b23e8 100644 --- a/src/mongo/db/auth/auth_name.cpp +++ b/src/mongo/db/auth/auth_name.cpp @@ -164,15 +164,6 @@ BSONObj AuthName<T>::toBSON(bool encodeTenant) const { return bob.obj(); } -template <typename T> -std::size_t AuthName<T>::getBSONObjSize() const { - return 4UL + // BSONObj size - 1UL + T::kFieldName.size() + 1UL + // FieldName elem type, FieldName, terminating NULL. - 4UL + getName().size() + 1UL + // Length of name data, name data, terminating NULL. - 1UL + ("db"_sd).size() + 1UL + // DB field elem type, "db", terminating NULL. - 4UL + getDB().size() + 1UL + // DB value length, DB value, terminating NULL. - 1UL; // EOD marker. -} // Materialize the types we care about. template class AuthName<RoleName>; diff --git a/src/mongo/db/auth/auth_name.h b/src/mongo/db/auth/auth_name.h index 20a5e279fcd..62fd1d6fa8e 100644 --- a/src/mongo/db/auth/auth_name.h +++ b/src/mongo/db/auth/auth_name.h @@ -91,8 +91,6 @@ public: void appendToBSON(BSONObjBuilder* bob, bool encodeTenant = false) const; BSONObj toBSON(bool encodeTenant = false) const; - std::size_t getBSONObjSize() const; - /** * Gets the name part of a AuthName. */ diff --git a/src/mongo/db/auth/auth_op_observer.h b/src/mongo/db/auth/auth_op_observer.h index f0afcd2a860..c145ebc3371 100644 --- a/src/mongo/db/auth/auth_op_observer.h +++ b/src/mongo/db/auth/auth_op_observer.h @@ -206,10 +206,6 @@ public: size_t numberOfPrePostImagesToWrite, Date_t wallClockTime) final {} - void onTransactionPrepareNonPrimary(OperationContext* opCtx, - const std::vector<repl::OplogEntry>& statements, - const repl::OpTime& prepareOpTime) final {} - void onTransactionAbort(OperationContext* opCtx, boost::optional<OplogSlot> abortOplogEntryOpTime) final {} diff --git a/src/mongo/db/auth/authentication_session.cpp b/src/mongo/db/auth/authentication_session.cpp index 97ae7654d01..30d6f74fc31 100644 --- a/src/mongo/db/auth/authentication_session.cpp +++ b/src/mongo/db/auth/authentication_session.cpp @@ -40,35 +40,21 @@ namespace mongo { namespace { constexpr auto kDiagnosticLogLevel = 3; -Status crossVerifyUserNames(const UserName& oldUser, - const UserName& newUser, - const bool isMechX509) noexcept { +Status crossVerifyUserNames(const UserName& oldUser, const UserName& newUser) noexcept { if (oldUser.empty()) { return Status::OK(); } - // There are some special cases around __system where a switch in the username is acceptable. - if (oldUser.getUser() == "__system") { - // If the new user is on $external and X.509 auth is being used, then any username is - // allowed. - if (newUser.getDB() == "$external" && isMechX509) { - return Status::OK(); - } - } - - // Allow a switch from an empty user on admin to __system@local if enableTestCommands is true. - // This is needed for auth passthrough suites on mongos. - if (getTestCommandsEnabled() && oldUser.getUser().empty() && oldUser.getDB() == "admin" && - newUser.getUser() == "__system" && newUser.getDB() == "local") { - return Status::OK(); - } + if (!getTestCommandsEnabled()) { + // Authenticating the __system@local user to the admin database on mongos is required + // by the auth passthrough test suite, hence we forgive this set of errors in testing. - // Barring special cases, both the database and the username must be the same. - if (oldUser.getDB() != newUser.getDB()) { - return { - ErrorCodes::ProtocolError, - str::stream() << "Attempt to switch database target during SASL authentication from " - << oldUser << " to " << newUser}; + if (oldUser.getDB() != newUser.getDB()) { + return {ErrorCodes::ProtocolError, + str::stream() + << "Attempt to switch database target during SASL authentication from " + << oldUser << " to " << newUser}; + } } if (oldUser.getUser().empty() || newUser.getUser().empty()) { @@ -215,9 +201,8 @@ void AuthenticationSession::setMechanismName(StringData mechanismName) { } } -void AuthenticationSession::_verifyUserNameFromSaslSupportedMechanisms(const UserName& userName, - const bool isMechX509) { - if (auto status = crossVerifyUserNames(_ssmUserName, userName, isMechX509); !status.isOK()) { +void AuthenticationSession::_verifyUserNameFromSaslSupportedMechanisms(const UserName& userName) { + if (auto status = crossVerifyUserNames(_ssmUserName, userName); !status.isOK()) { LOGV2(5286202, "Different user name was supplied to saslSupportedMechs", "error"_attr = status); @@ -239,20 +224,20 @@ void AuthenticationSession::setUserNameForSaslSupportedMechanisms(UserName userN "Set user name for session", "userName"_attr = userName, "oldName"_attr = _userName); - _verifyUserNameFromSaslSupportedMechanisms(userName, false /* isMechX509 */); + _verifyUserNameFromSaslSupportedMechanisms(userName); _ssmUserName = userName; } -void AuthenticationSession::updateUserName(UserName userName, bool isMechX509) { +void AuthenticationSession::updateUserName(UserName userName) { LOGV2_DEBUG(5286203, kDiagnosticLogLevel, "Updating user name for session", "userName"_attr = userName, "oldName"_attr = _userName); - _verifyUserNameFromSaslSupportedMechanisms(userName, isMechX509); - uassertStatusOK(crossVerifyUserNames(_userName, userName, isMechX509)); + _verifyUserNameFromSaslSupportedMechanisms(userName); + uassertStatusOK(crossVerifyUserNames(_userName, userName)); _userName = userName; } @@ -287,8 +272,7 @@ void AuthenticationSession::_finish() { if (_mech->isClusterMember()) { setAsClusterMember(); } - updateUserName({_mech->getPrincipalName(), _mech->getAuthenticationDatabase()}, - _mechName == auth::kMechanismMongoX509); + updateUserName({_mech->getPrincipalName(), _mech->getAuthenticationDatabase()}); } } diff --git a/src/mongo/db/auth/authentication_session.h b/src/mongo/db/auth/authentication_session.h index 09206ab8b21..0b95b4ed2fb 100644 --- a/src/mongo/db/auth/authentication_session.h +++ b/src/mongo/db/auth/authentication_session.h @@ -145,7 +145,7 @@ public: * The database will be validated against the current database for this session. */ void updateDatabase(StringData database) { - updateUserName(UserName("", database.toString()), false /* isMechX509 */); + updateUserName(UserName("", database.toString())); } /** @@ -153,7 +153,7 @@ public: * * The user name will be validated against the current user name for this session. */ - void updateUserName(UserName userName, bool isMechX509); + void updateUserName(UserName userName); /** * Set the last user name used with `saslSupportedMechs` for this session. @@ -235,7 +235,7 @@ private: static boost::optional<AuthenticationSession>& _get(Client* client); void _finish(); - void _verifyUserNameFromSaslSupportedMechanisms(const UserName& user, bool isMechX509); + void _verifyUserNameFromSaslSupportedMechanisms(const UserName& user); Client* const _client; diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp index 771abcf427b..93450c8b1f5 100644 --- a/src/mongo/db/auth/authorization_manager_impl.cpp +++ b/src/mongo/db/auth/authorization_manager_impl.cpp @@ -675,35 +675,35 @@ void AuthorizationManagerImpl::_pinnedUsersThreadRoutine() noexcept try { void AuthorizationManagerImpl::invalidateUserByName(OperationContext* opCtx, const UserName& userName) { LOGV2_DEBUG(20235, 2, "Invalidating user", "user"_attr = userName); + _updateCacheGeneration(); _authSchemaVersionCache.invalidateAll(); // Invalidate the named User, assuming no externally provided roles. When roles are defined // externally, there exists no user document which may become invalid. _userCache.invalidateKey(UserRequest(userName, boost::none)); - _updateCacheGeneration(); } void AuthorizationManagerImpl::invalidateUsersFromDB(OperationContext* opCtx, StringData dbname) { LOGV2_DEBUG(20236, 2, "Invalidating all users from database", "database"_attr = dbname); + _updateCacheGeneration(); _authSchemaVersionCache.invalidateAll(); _userCache.invalidateKeyIf( [&](const UserRequest& userRequest) { return userRequest.name.getDB() == dbname; }); - _updateCacheGeneration(); } void AuthorizationManagerImpl::invalidateUsersByTenant(OperationContext* opCtx, const TenantId& tenant) { LOGV2_DEBUG(6323600, 2, "Invalidating tenant users", "tenant"_attr = tenant); + _updateCacheGeneration(); _authSchemaVersionCache.invalidateAll(); _userCache.invalidateKeyIf( [&](const UserRequest& userRequest) { return userRequest.name.getTenant() == tenant; }); - _updateCacheGeneration(); } void AuthorizationManagerImpl::invalidateUserCache(OperationContext* opCtx) { LOGV2_DEBUG(20237, 2, "Invalidating user cache"); + _updateCacheGeneration(); _authSchemaVersionCache.invalidateAll(); _userCache.invalidateAll(); - _updateCacheGeneration(); } Status AuthorizationManagerImpl::refreshExternalUsers(OperationContext* opCtx) { diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp index a657784f660..8c2be85d37c 100644 --- a/src/mongo/db/auth/authorization_session_impl.cpp +++ b/src/mongo/db/auth/authorization_session_impl.cpp @@ -715,6 +715,20 @@ void AuthorizationSessionImpl::_refreshUserInfoAsNeeded(OperationContext* opCtx) auto swUser = authMan.reacquireUser(opCtx, currentUser); if (!swUser.isOK()) { auto& status = swUser.getStatus(); + // If an external user is no longer in the cache and cannot be acquired from the cache's + // backing external service, it should be removed from _authenticatedUsers. This + // guarantees that no operations can be performed until the external authorization + // provider comes back up. + if (name.getDB() == "$external"_sd) { + removeUser(it++); + LOGV2(5914804, + "Removed external user from session cache of user information because of " + "error status", + "user"_attr = name, + "status"_attr = status); + continue; // No need to advance "it" in this case. + } + switch (status.code()) { case ErrorCodes::UserNotFound: { // User does not exist anymore; remove it from _authenticatedUsers. diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 237997f232e..4ecb9cca692 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -33,21 +33,115 @@ #include "mongo/base/status.h" #include "mongo/bson/bson_depth.h" +#include "mongo/crypto/mechanism_scram.h" +#include "mongo/crypto/sha1_block.h" +#include "mongo/crypto/sha256_block.h" +#include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_checks.h" -#include "mongo/db/auth/authorization_session_test_fixture.h" +#include "mongo/db/auth/authorization_manager_impl.h" +#include "mongo/db/auth/authorization_session_for_test.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/restriction_environment.h" +#include "mongo/db/auth/sasl_options.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" +#include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/pipeline/aggregation_request_helper.h" +#include "mongo/db/service_context_test_fixture.h" #include "mongo/idl/server_parameter_test_util.h" #include "mongo/transport/session.h" #include "mongo/transport/transport_layer_mock.h" #include "mongo/unittest/unittest.h" namespace mongo { - namespace { -using AuthorizationSessionTest = AuthorizationSessionTestFixture; + +class FailureCapableAuthzManagerExternalStateMock : public AuthzManagerExternalStateMock { +public: + FailureCapableAuthzManagerExternalStateMock() = default; + ~FailureCapableAuthzManagerExternalStateMock() = default; + + void setFindsShouldFail(bool enable) { + _findsShouldFail = enable; + } + + Status findOne(OperationContext* opCtx, + const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) override { + if (_findsShouldFail && collectionName == AuthorizationManager::usersCollectionNamespace) { + return Status(ErrorCodes::UnknownError, + "findOne on admin.system.users set to fail in mock."); + } + return AuthzManagerExternalStateMock::findOne(opCtx, collectionName, query, result); + } + +private: + bool _findsShouldFail{false}; +}; + +class AuthorizationSessionTest : public ScopedGlobalServiceContextForTest, public unittest::Test { +public: + void setUp() { + _session = transportLayer.createSession(); + _client = getServiceContext()->makeClient("testClient", _session); + RestrictionEnvironment::set( + _session, std::make_unique<RestrictionEnvironment>(SockAddr(), SockAddr())); + _opCtx = _client->makeOperationContext(); + auto localManagerState = std::make_unique<FailureCapableAuthzManagerExternalStateMock>(); + managerState = localManagerState.get(); + managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final); + auto uniqueAuthzManager = std::make_unique<AuthorizationManagerImpl>( + getServiceContext(), std::move(localManagerState)); + authzManager = uniqueAuthzManager.get(); + AuthorizationManager::set(getServiceContext(), std::move(uniqueAuthzManager)); + auto localSessionState = std::make_unique<AuthzSessionExternalStateMock>(authzManager); + sessionState = localSessionState.get(); + authzSession = std::make_unique<AuthorizationSessionForTest>( + std::move(localSessionState), + AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{}); + authzManager->setAuthEnabled(true); + + credentials = + BSON("SCRAM-SHA-1" << scram::Secrets<SHA1Block>::generateCredentials( + "a", saslGlobalParams.scramSHA1IterationCount.load()) + << "SCRAM-SHA-256" + << scram::Secrets<SHA256Block>::generateCredentials( + "a", saslGlobalParams.scramSHA256IterationCount.load())); + } + + void tearDown() override { + authzSession->logoutAllDatabases(_client.get(), "Ending AuthorizationSessionTest"); + } + + Status createUser(const UserName& username, const std::vector<RoleName>& roles) { + BSONObjBuilder userDoc; + userDoc.append("_id", username.getUnambiguousName()); + username.appendToBSON(&userDoc); + userDoc.append("credentials", credentials); + + BSONArrayBuilder rolesBSON(userDoc.subarrayStart("roles")); + for (const auto& role : roles) { + role.serializeToBSON(&rolesBSON); + } + rolesBSON.doneFast(); + + return managerState->insertPrivilegeDocument(_opCtx.get(), userDoc.obj(), {}); + } + +protected: + FailureCapableAuthzManagerExternalStateMock* managerState; + transport::TransportLayerMock transportLayer; + transport::SessionHandle _session; + ServiceContext::UniqueClient _client; + ServiceContext::UniqueOperationContext _opCtx; + AuthzSessionExternalStateMock* sessionState; + AuthorizationManager* authzManager; + std::unique_ptr<AuthorizationSessionForTest> authzSession; + BSONObj credentials; +}; const NamespaceString testFooNss("test.foo"); const NamespaceString testBarNss("test.bar"); @@ -1432,22 +1526,5 @@ TEST_F(AuthorizationSessionTest, MayBypassWriteBlockingModeIsSetCorrectly) { ASSERT_FALSE(authzSession->mayBypassWriteBlockingMode()); } -TEST_F(AuthorizationSessionTest, InternalSystemClientsBypassValidateRestrictions) { - // set up a direct client without transport session - auto client = getServiceContext()->makeClient("directClient"); - // set Client user to be the internal __system user. - authzSession->grantInternalAuthorization(client.get()); - auto opCtx = client->makeOperationContext(); - - // invalidate the __system user to force the next request to validate restrictions - (*internalSecurity.getUser())->invalidate(); - - // should not fail even though client does not have a transport session - authzSession->startRequest(opCtx.get()); - - User* currentUser = authzSession->getSingleUser(); - ASSERT_OK(currentUser->validateRestrictions(opCtx.get())); -} - } // namespace } // namespace mongo diff --git a/src/mongo/db/auth/authorization_session_test_fixture.cpp b/src/mongo/db/auth/authorization_session_test_fixture.cpp deleted file mode 100644 index 330837ee719..00000000000 --- a/src/mongo/db/auth/authorization_session_test_fixture.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (C) 2023-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/db/auth/authorization_session_test_fixture.h" - -#include <vector> - -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/crypto/mechanism_scram.h" -#include "mongo/crypto/sha1_block.h" -#include "mongo/crypto/sha256_block.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/restriction_environment.h" -#include "mongo/db/auth/sasl_options.h" -#include "mongo/db/namespace_string.h" -namespace mongo { - -void AuthorizationSessionTestFixture::setUp() { - _session = transportLayer.createSession(); - _client = getServiceContext()->makeClient("testClient", _session); - RestrictionEnvironment::set(_session, - std::make_unique<RestrictionEnvironment>(SockAddr(), SockAddr())); - _opCtx = _client->makeOperationContext(); - auto localManagerState = std::make_unique<FailureCapableAuthzManagerExternalStateMock>(); - managerState = localManagerState.get(); - managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final); - auto uniqueAuthzManager = std::make_unique<AuthorizationManagerImpl>( - getServiceContext(), std::move(localManagerState)); - authzManager = uniqueAuthzManager.get(); - AuthorizationManager::set(getServiceContext(), std::move(uniqueAuthzManager)); - auto localSessionState = std::make_unique<AuthzSessionExternalStateMock>(authzManager); - sessionState = localSessionState.get(); - authzSession = std::make_unique<AuthorizationSessionForTest>( - std::move(localSessionState), AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{}); - authzManager->setAuthEnabled(true); - - credentials = - BSON("SCRAM-SHA-1" << scram::Secrets<SHA1Block>::generateCredentials( - "a", saslGlobalParams.scramSHA1IterationCount.load()) - << "SCRAM-SHA-256" - << scram::Secrets<SHA256Block>::generateCredentials( - "a", saslGlobalParams.scramSHA256IterationCount.load())); -} - -Status AuthorizationSessionTestFixture::createUser(const UserName& username, - const std::vector<RoleName>& roles) { - BSONObjBuilder userDoc; - userDoc.append("_id", username.getUnambiguousName()); - username.appendToBSON(&userDoc); - userDoc.append("credentials", credentials); - - BSONArrayBuilder rolesBSON(userDoc.subarrayStart("roles")); - for (const auto& role : roles) { - role.serializeToBSON(&rolesBSON); - } - rolesBSON.doneFast(); - - return managerState->insertPrivilegeDocument(_opCtx.get(), userDoc.obj(), {}); -} -} // namespace mongo diff --git a/src/mongo/db/auth/authorization_session_test_fixture.h b/src/mongo/db/auth/authorization_session_test_fixture.h deleted file mode 100644 index 7e80999ca5f..00000000000 --- a/src/mongo/db/auth/authorization_session_test_fixture.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (C) 2023-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 <vector> - -#include "mongo/db/auth/authorization_manager_impl.h" -#include "mongo/db/auth/authorization_session_for_test.h" -#include "mongo/db/auth/authz_manager_external_state_mock.h" -#include "mongo/db/auth/authz_session_external_state_mock.h" -#include "mongo/db/service_context_d_test_fixture.h" -#include "mongo/transport/transport_layer_mock.h" - -namespace mongo { - -class FailureCapableAuthzManagerExternalStateMock : public AuthzManagerExternalStateMock { -public: - FailureCapableAuthzManagerExternalStateMock() = default; - ~FailureCapableAuthzManagerExternalStateMock() = default; - - void setFindsShouldFail(bool enable) { - _findsShouldFail = enable; - } - - Status findOne(OperationContext* opCtx, - const NamespaceString& collectionName, - const BSONObj& query, - BSONObj* result) override { - if (_findsShouldFail && collectionName == AuthorizationManager::usersCollectionNamespace) { - return Status(ErrorCodes::UnknownError, - "findOne on admin.system.users set to fail in mock."); - } - return AuthzManagerExternalStateMock::findOne(opCtx, collectionName, query, result); - } - -private: - bool _findsShouldFail{false}; -}; - -class AuthorizationSessionTestFixture : public ServiceContextMongoDTest { -public: - void setUp(); - - void tearDown() override { - authzSession->logoutAllDatabases(_client.get(), "Ending AuthorizationSessionTest"); - } - - Status createUser(const UserName& username, const std::vector<RoleName>& roles); - -protected: - FailureCapableAuthzManagerExternalStateMock* managerState; - transport::TransportLayerMock transportLayer; - transport::SessionHandle _session; - ServiceContext::UniqueClient _client; - ServiceContext::UniqueOperationContext _opCtx; - AuthzSessionExternalStateMock* sessionState; - AuthorizationManager* authzManager; - std::unique_ptr<AuthorizationSessionForTest> authzSession; - BSONObj credentials; -}; -} // namespace mongo diff --git a/src/mongo/db/auth/builtin_roles.cpp b/src/mongo/db/auth/builtin_roles.cpp index 9eddd117f80..2b0c63cb798 100644 --- a/src/mongo/db/auth/builtin_roles.cpp +++ b/src/mongo/db/auth/builtin_roles.cpp @@ -119,7 +119,6 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { << ActionType::killCursors << ActionType::listCollections << ActionType::listIndexes - << ActionType::listSearchIndexes << ActionType::planCacheRead; // Read-write role @@ -129,15 +128,12 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { << ActionType::convertToCapped // db admin gets this also << ActionType::createCollection // db admin gets this also << ActionType::createIndex - << ActionType::createSearchIndexes << ActionType::dropCollection << ActionType::dropIndex - << ActionType::dropSearchIndex << ActionType::insert << ActionType::remove << ActionType::renameCollectionSameDB // db admin gets this also - << ActionType::update - << ActionType::updateSearchIndex; + << ActionType::update; // User admin role userAdminRoleActions @@ -167,24 +163,21 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { << ActionType::dropDatabase // clusterAdmin gets this also TODO(spencer): should // readWriteAnyDatabase? << ActionType::dropIndex - << ActionType::dropSearchIndex << ActionType::createIndex - << ActionType::createSearchIndexes << ActionType::enableProfiler << ActionType::listCollections << ActionType::listIndexes - << ActionType::listSearchIndexes << ActionType::planCacheIndexFilter << ActionType::planCacheRead << ActionType::planCacheWrite << ActionType::reIndex << ActionType::renameCollectionSameDB // read_write gets this also << ActionType::storageDetails - << ActionType::updateSearchIndex << ActionType::validate; // clusterMonitor role actions that target the cluster resource clusterMonitorRoleClusterActions + << ActionType::checkFreeMonitoringStatus << ActionType::connPoolStats << ActionType::getCmdLineOpts << ActionType::getDefaultRWConcern // clusterManager gets this also @@ -203,11 +196,7 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { << ActionType::top << ActionType::useUUID << ActionType::inprog - << ActionType::shardingState - << ActionType::allCollectionStats - << ActionType::shardedDataDistribution - << ActionType::queryStatsRead - << ActionType::queryStatsReadTransformed; + << ActionType::shardingState; // clusterMonitor role actions that target a database (or collection) resource clusterMonitorRoleDatabaseActions @@ -264,6 +253,7 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) { << ActionType::runTenantMigration << ActionType::setDefaultRWConcern << ActionType::setFeatureCompatibilityVersion + << ActionType::setFreeMonitoring << ActionType::setClusterParameter << ActionType::getClusterParameter; @@ -376,8 +366,7 @@ void addUserAdminAnyDbPrivileges(PrivilegeVector* privileges) { ActionSet readRoleAndIndexActions; readRoleAndIndexActions += readRoleActions; - readRoleAndIndexActions << ActionType::createIndex << ActionType::dropIndex - << ActionType::createSearchIndexes << ActionType::dropSearchIndex; + readRoleAndIndexActions << ActionType::createIndex << ActionType::dropIndex; Privilege::addPrivilegeToPrivilegeVector( privileges, Privilege(ResourcePattern::forCollectionName("system.users"), readRoleActions)); @@ -433,11 +422,6 @@ void addClusterMonitorPrivileges(PrivilegeVector* privileges) { Privilege(ResourcePattern::forDatabaseName("config"), clusterMonitorRoleDatabaseActions)); Privilege::addPrivilegeToPrivilegeVector( privileges, - Privilege(ResourcePattern::forExactNamespace(NamespaceString("config", "system.sessions")), - clusterMonitorRoleDatabaseActions)); - - Privilege::addPrivilegeToPrivilegeVector( - privileges, Privilege(ResourcePattern::forDatabaseName("local"), clusterMonitorRoleDatabaseActions)); addReadOnlyDbPrivileges(privileges, "config"); addReadOnlyDbPrivileges(privileges, "local"); @@ -535,8 +519,6 @@ void addQueryableBackupPrivileges(PrivilegeVector* privileges) { Privilege::addPrivilegeToPrivilegeVector( privileges, Privilege(ResourcePattern::forAnyResource(), ActionType::listIndexes)); Privilege::addPrivilegeToPrivilegeVector( - privileges, Privilege(ResourcePattern::forAnyResource(), ActionType::listSearchIndexes)); - Privilege::addPrivilegeToPrivilegeVector( privileges, Privilege(ResourcePattern::forAnySystemBuckets(), ActionType::find)); ActionSet clusterActions; @@ -617,9 +599,7 @@ void addRestorePrivileges(PrivilegeVector* privileges) { ActionSet actions; actions << ActionType::bypassDocumentValidation << ActionType::collMod << ActionType::convertToCapped << ActionType::createCollection - << ActionType::createIndex << ActionType::dropCollection - << ActionType::createSearchIndexes << ActionType::updateSearchIndex - << ActionType::insert; + << ActionType::createIndex << ActionType::dropCollection << ActionType::insert; Privilege::addPrivilegeToPrivilegeVector( privileges, Privilege(ResourcePattern::forAnyNormalResource(), actions)); @@ -696,11 +676,6 @@ void addRestorePrivileges(PrivilegeVector* privileges) { Privilege( ResourcePattern::forExactNamespace(AuthorizationManager::rolesCollectionNamespace), ActionType::createIndex)); - Privilege::addPrivilegeToPrivilegeVector( - privileges, - Privilege( - ResourcePattern::forExactNamespace(AuthorizationManager::rolesCollectionNamespace), - ActionType::createSearchIndexes)); Privilege::addPrivilegeToPrivilegeVector( privileges, @@ -712,12 +687,7 @@ void addRestorePrivileges(PrivilegeVector* privileges) { // Need to be able to set and bypass write blocking mode for C2C replication ActionType::bypassWriteBlockingMode, ActionType::setUserWriteBlockMode, - // Needed for `mongorestore --preserveUUID` - ActionType::applyOps, })); - Privilege::addPrivilegeToPrivilegeVector( - privileges, - Privilege(ResourcePattern::forCollectionName("system.views"), ActionType::dropCollection)); } void addRootRolePrivileges(PrivilegeVector* privileges) { diff --git a/src/mongo/db/auth/builtin_roles_test.cpp b/src/mongo/db/auth/builtin_roles_test.cpp index ebf87660db7..15b5aa932fd 100644 --- a/src/mongo/db/auth/builtin_roles_test.cpp +++ b/src/mongo/db/auth/builtin_roles_test.cpp @@ -108,7 +108,6 @@ TEST(BuiltinRoles, addPrivilegesForBuiltinRole) { ActionType::killCursors, ActionType::listCollections, ActionType::listIndexes, - ActionType::listSearchIndexes, ActionType::planCacheRead, }); const auto adminDB = ResourcePattern::forDatabaseName("admin"); diff --git a/src/mongo/db/auth/resource_pattern.h b/src/mongo/db/auth/resource_pattern.h index 67c00c9878b..5b4a952b886 100644 --- a/src/mongo/db/auth/resource_pattern.h +++ b/src/mongo/db/auth/resource_pattern.h @@ -130,9 +130,7 @@ public: */ static ResourcePattern forExactSystemBucketsCollection(StringData dbName, StringData collectionName) { - uassert(ErrorCodes::InvalidNamespace, - "Invalid namespace '{}.system.buckets.{}'"_format(dbName, collectionName), - !collectionName.startsWith("system.buckets.")); + invariant(!collectionName.startsWith("system.buckets.")); return ResourcePattern(MatchTypeEnum::kMatchExactSystemBucketResource, NamespaceString(dbName, collectionName)); } diff --git a/src/mongo/db/auth/sasl_commands.h b/src/mongo/db/auth/sasl_commands.h index 57dcb585794..054756745e6 100644 --- a/src/mongo/db/auth/sasl_commands.h +++ b/src/mongo/db/auth/sasl_commands.h @@ -36,7 +36,7 @@ namespace mongo { class OperationContext; /** - * Handle hello: { speculativeAuthenticate: {...} } + * Handle isMaster: { speculativeAuthenticate: {...} } */ void doSpeculativeSaslStart(OperationContext* opCtx, const BSONObj& sourceObj, diff --git a/src/mongo/db/auth/sasl_mechanism_registry.h b/src/mongo/db/auth/sasl_mechanism_registry.h index 921ae18ce3a..06b0850125b 100644 --- a/src/mongo/db/auth/sasl_mechanism_registry.h +++ b/src/mongo/db/auth/sasl_mechanism_registry.h @@ -104,12 +104,12 @@ public: virtual SecurityPropertySet properties() const = 0; /** - * This returns a number that represents the "amount" of security provided by this mechanism to - * determine the order in which it is offered to clients in the "hello" saslSupportedMechs - * response. + * This returns a number that represents the "amount" of security provided by this mechanism + * to determine the order in which it is offered to clients in the isMaster + * saslSupportedMechs response. * - * The value of securityLevel is arbitrary so long as the more secure mechanisms return a higher - * value than the less secure mechanisms. + * The value of securityLevel is arbitrary so long as the more secure mechanisms return a + * higher value than the less secure mechanisms. * * For example, SCRAM-SHA-256 > SCRAM-SHA-1 > PLAIN */ diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp index dba96b1f474..a418cfb8eb2 100644 --- a/src/mongo/db/auth/user.cpp +++ b/src/mongo/db/auth/user.cpp @@ -179,12 +179,6 @@ void User::setIndirectRestrictions(RestrictionDocuments restrictions) & { } Status User::validateRestrictions(OperationContext* opCtx) const { - if (!opCtx->getClient()->session()) { - // If Client has no transport session, it must be internal system connection - invariant(opCtx->getClient()->isFromSystemConnection()); - return Status::OK(); - } - const auto& env = RestrictionEnvironment::get(*(opCtx->getClient())); auto status = _restrictions.validate(env); if (!status.isOK()) { |
