diff options
Diffstat (limited to 'src/mongo')
36 files changed, 672 insertions, 651 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index d2c4e1bda40..922e63dc38f 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1221,6 +1221,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/auth/auth_checks', '$BUILD_DIR/mongo/db/index/index_access_methods', '$BUILD_DIR/mongo/db/s/resharding_util', '$BUILD_DIR/mongo/s/common_s', diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index e128915a769..5d1890e92d9 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -77,6 +77,9 @@ env.Library( LIBDEPS=[ 'auth_impl_internal', ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/concurrency/lock_manager', + ] ) env.Library( @@ -86,7 +89,6 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/bson/mutable/mutable_bson', 'auth', 'auth_options', 'authprivilege', @@ -100,7 +102,6 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/bson/mutable/mutable_bson', '$BUILD_DIR/mongo/bson/util/bson_extract', 'auth', 'user', @@ -134,14 +135,10 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/base/secure_allocator', - '$BUILD_DIR/mongo/bson/mutable/mutable_bson', '$BUILD_DIR/mongo/bson/util/bson_extract', - '$BUILD_DIR/mongo/db/catalog/document_validation', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/db/global_settings', '$BUILD_DIR/mongo/db/namespace_string', - '$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source', - '$BUILD_DIR/mongo/db/update/update_driver', '$BUILD_DIR/mongo/util/concurrency/thread_pool', '$BUILD_DIR/mongo/util/icu', '$BUILD_DIR/mongo/util/net/ssl_manager', @@ -165,6 +162,31 @@ env.Library( ) env.Library( + target='auth_checks', + source=[ + 'authorization_checks.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/catalog/document_validation', + '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/namespace_string', + '$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source', + '$BUILD_DIR/mongo/db/update/update_driver', + 'auth', + 'authorization_manager_global', + 'authprivilege', + 'builtin_roles', + 'user', + 'user_document_parser', + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/audit', + '$BUILD_DIR/mongo/idl/server_parameter', + ], +) + +env.Library( target='authprivilege', source=[ 'action_set.cpp', diff --git a/src/mongo/db/auth/authorization_checks.cpp b/src/mongo/db/auth/authorization_checks.cpp new file mode 100644 index 00000000000..9877223dc89 --- /dev/null +++ b/src/mongo/db/auth/authorization_checks.cpp @@ -0,0 +1,318 @@ +/** + * 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. + */ + +#include "mongo/db/auth/authorization_checks.h" + +#include "mongo/db/catalog/document_validation.h" +#include "mongo/db/pipeline/aggregation_request_helper.h" +#include "mongo/db/pipeline/lite_parsed_pipeline.h" + +namespace mongo::auth { + +namespace { + +// Checks if this connection has the privileges necessary to create or modify the view 'viewNs' +// to be a view on 'viewOnNs' with pipeline 'viewPipeline'. Call this function after verifying +// that the user has the 'createCollection' or 'collMod' action, respectively. +Status checkAuthForCreateOrModifyView(AuthorizationSession* authzSession, + const NamespaceString& viewNs, + const NamespaceString& viewOnNs, + const BSONArray& viewPipeline, + bool isMongos) { + // It's safe to allow a user to create or modify a view if they can't read it anyway. + if (!authzSession->isAuthorizedForActionsOnNamespace(viewNs, ActionType::find)) { + return Status::OK(); + } + + auto request = aggregation_request_helper::parseFromBSON( + viewNs, + BSON("aggregate" << viewOnNs.coll() << "pipeline" << viewPipeline << "cursor" << BSONObj() + << "$db" << viewOnNs.db()), + boost::none, + false); + + auto statusWithPrivs = getPrivilegesForAggregate(authzSession, viewOnNs, request, isMongos); + PrivilegeVector privileges = uassertStatusOK(statusWithPrivs); + if (!authzSession->isAuthorizedForPrivileges(privileges)) { + return Status(ErrorCodes::Unauthorized, "unauthorized"); + } + return Status::OK(); +} + +} // namespace + + +Status checkAuthForFind(AuthorizationSession* authSession, + const NamespaceString& ns, + bool hasTerm) { + if (MONGO_unlikely(ns.isCommand())) { + return Status(ErrorCodes::InternalError, + str::stream() << "Checking query auth on command namespace " << ns.ns()); + } + if (!authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::find)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for query on " << ns.ns()); + } + + // Only internal clients (such as other nodes in a replica set) are allowed to use + // the 'term' field in a find operation. Use of this field could trigger changes + // in the receiving server's replication state and should be protected. + if (hasTerm && + !authSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for query with term on " << ns.ns()); + } + + return Status::OK(); +} + +Status checkAuthForGetMore(AuthorizationSession* authSession, + const NamespaceString& ns, + long long cursorID, + bool hasTerm) { + // Since users can only getMore their own cursors, we verify that a user either is authenticated + // or does not need to be. + if (!authSession->shouldIgnoreAuthChecks() && !authSession->isAuthenticated()) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for getMore on " << ns.db()); + } + + // Only internal clients (such as other nodes in a replica set) are allowed to use + // the 'term' field in a getMore operation. Use of this field could trigger changes + // in the receiving server's replication state and should be protected. + if (hasTerm && + !authSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::internal)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for getMore with term on " << ns.ns()); + } + + return Status::OK(); +} + +Status checkAuthForInsert(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns) { + ActionSet required{ActionType::insert}; + if (DocumentValidationSettings::get(opCtx).isSchemaValidationDisabled()) { + required.addAction(ActionType::bypassDocumentValidation); + } + if (!authSession->isAuthorizedForActionsOnNamespace(ns, required)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for insert on " << ns.ns()); + } + + return Status::OK(); +} + +Status checkAuthForUpdate(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns, + const BSONObj& query, + const write_ops::UpdateModification& update, + bool upsert) { + ActionSet required{ActionType::update}; + StringData operationType = "update"_sd; + + if (upsert) { + required.addAction(ActionType::insert); + operationType = "upsert"_sd; + } + + if (DocumentValidationSettings::get(opCtx).isSchemaValidationDisabled()) { + required.addAction(ActionType::bypassDocumentValidation); + } + + if (!authSession->isAuthorizedForActionsOnNamespace(ns, required)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized for " << operationType << " on " << ns.ns()); + } + + return Status::OK(); +} + +Status checkAuthForDelete(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns, + const BSONObj& query) { + if (!authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized to remove from " << ns.ns()); + } + return Status::OK(); +} + +Status checkAuthForKillCursors(AuthorizationSession* authSession, + const NamespaceString& ns, + UserNameIterator cursorOwner) { + if (authSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), + ActionType::killAnyCursor)) { + return Status::OK(); + } + + if (authSession->isCoauthorizedWith(cursorOwner)) { + return Status::OK(); + } + + ResourcePattern target; + if (ns.isListCollectionsCursorNS()) { + target = ResourcePattern::forDatabaseName(ns.db()); + } else { + target = ResourcePattern::forExactNamespace(ns); + } + + if (authSession->isAuthorizedForActionsOnResource(target, ActionType::killAnyCursor)) { + return Status::OK(); + } + + return Status(ErrorCodes::Unauthorized, + str::stream() << "not authorized to kill cursor on " << ns.ns()); +} + +Status checkAuthForCreate(AuthorizationSession* authSession, + const CreateCommand& cmd, + bool isMongos) { + auto ns = cmd.getNamespace(); + + if (cmd.getCapped() && + !authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::convertToCapped)) { + return Status(ErrorCodes::Unauthorized, "unauthorized"); + } + + const bool hasCreateCollectionAction = + authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::createCollection); + + // If attempting to create a view, check for additional required privileges. + if (auto optViewOn = cmd.getViewOn()) { + + // You need the createCollection action on this namespace; the insert action is not + // sufficient. + if (!hasCreateCollectionAction) { + return {ErrorCodes::Unauthorized, "unauthorized"}; + } + + // Parse the viewOn namespace and the pipeline. If no pipeline was specified, use the empty + // pipeline. + NamespaceString viewOnNs(ns.db(), optViewOn.get()); + auto pipeline = cmd.getPipeline().get_value_or(std::vector<BSONObj>()); + BSONArrayBuilder pipelineArray; + for (const auto& stage : pipeline) { + pipelineArray.append(stage); + } + return checkAuthForCreateOrModifyView( + authSession, ns, viewOnNs, pipelineArray.arr(), isMongos); + } + + // To create a regular collection, ActionType::createCollection or ActionType::insert are + // both acceptable. + if (hasCreateCollectionAction || + authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) { + return Status::OK(); + } + + return Status(ErrorCodes::Unauthorized, "unauthorized"); +} + +Status checkAuthForCollMod(AuthorizationSession* authSession, + const NamespaceString& ns, + const BSONObj& cmdObj, + bool isMongos) { + if (!authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::collMod)) { + return Status(ErrorCodes::Unauthorized, "unauthorized"); + } + + // Check for additional required privileges if attempting to modify a view. When auth is + // enabled, users must specify both "viewOn" and "pipeline" together. This prevents a user from + // exposing more information in the original underlying namespace by only changing "pipeline", + // or looking up more information via the original pipeline by only changing "viewOn". + const bool hasViewOn = cmdObj.hasField("viewOn"); + const bool hasPipeline = cmdObj.hasField("pipeline"); + if (hasViewOn != hasPipeline) { + return Status( + ErrorCodes::InvalidOptions, + "Must specify both 'viewOn' and 'pipeline' when modifying a view and auth is enabled"); + } + if (hasViewOn) { + NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData()); + auto viewPipeline = BSONArray(cmdObj["pipeline"].Obj()); + return checkAuthForCreateOrModifyView(authSession, ns, viewOnNs, viewPipeline, isMongos); + } + + return Status::OK(); +} + + +StatusWith<PrivilegeVector> getPrivilegesForAggregate(AuthorizationSession* authSession, + const NamespaceString& nss, + const AggregateCommand& request, + bool isMongos) { + if (!nss.isValid()) { + return Status(ErrorCodes::InvalidNamespace, + str::stream() << "Invalid input namespace, " << nss.ns()); + } + + PrivilegeVector privileges; + + // If this connection does not need to be authenticated (for instance, if auth is disabled), + // returns an empty requirements set. + if (authSession->shouldIgnoreAuthChecks()) { + return privileges; + } + + const auto& pipeline = request.getPipeline(); + + // If the aggregation pipeline is empty, confirm the user is authorized for find on 'nss'. + if (pipeline.empty()) { + Privilege currentPriv = + Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find); + Privilege::addPrivilegeToPrivilegeVector(&privileges, currentPriv); + return privileges; + } + + // If the first stage of the pipeline is not an initial source, the pipeline is implicitly + // reading documents from the underlying collection. The client must be authorized to do so. + auto liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipeline[0]); + if (!liteParsedDocSource->isInitialSource()) { + Privilege currentPriv = + Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find); + Privilege::addPrivilegeToPrivilegeVector(&privileges, currentPriv); + } + + // Confirm privileges for the pipeline. + for (auto&& pipelineStage : pipeline) { + liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipelineStage); + PrivilegeVector currentPrivs = liteParsedDocSource->requiredPrivileges( + isMongos, request.getBypassDocumentValidation().value_or(false)); + Privilege::addPrivilegesToPrivilegeVector(&privileges, currentPrivs); + } + return privileges; +} + +} // namespace mongo::auth diff --git a/src/mongo/db/auth/authorization_checks.h b/src/mongo/db/auth/authorization_checks.h new file mode 100644 index 00000000000..4dc13cf5fe7 --- /dev/null +++ b/src/mongo/db/auth/authorization_checks.h @@ -0,0 +1,104 @@ +/** + * 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.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/user_set.h" +#include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/ops/write_ops_parsers.h" +#include "mongo/db/pipeline/aggregate_command_gen.h" + + +namespace mongo::auth { + +// Checks if this connection has the privileges necessary to perform a find operation +// on the supplied namespace identifier. +Status checkAuthForFind(AuthorizationSession* authSession, const NamespaceString& ns, bool hasTerm); + +// Checks if this connection has the privileges necessary to perform a getMore operation on +// the identified cursor, supposing that cursor is associated with the supplied namespace +// identifier. +Status checkAuthForGetMore(AuthorizationSession* authSession, + const NamespaceString& ns, + long long cursorID, + bool hasTerm); + +// Checks if this connection has the privileges necessary to perform the given update on the +// given namespace. +Status checkAuthForUpdate(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns, + const BSONObj& query, + const write_ops::UpdateModification& update, + bool upsert); + +// Checks if this connection has the privileges necessary to insert to the given namespace. +Status checkAuthForInsert(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns); + +// Checks if this connection has the privileges necessary to perform a delete on the given +// namespace. +Status checkAuthForDelete(AuthorizationSession* authSession, + OperationContext* opCtx, + const NamespaceString& ns, + const BSONObj& query); + +// Checks if this connection has the privileges necessary to perform a killCursor on +// the identified cursor, supposing that cursor is associated with the supplied namespace +// identifier. +Status checkAuthForKillCursors(AuthorizationSession* authSession, + const NamespaceString& cursorNss, + UserNameIterator cursorOwner); + +// Attempts to get the privileges necessary to run the aggregation pipeline specified in +// 'request' on the namespace 'ns' either directly on mongoD or via mongoS. +StatusWith<PrivilegeVector> getPrivilegesForAggregate(AuthorizationSession* authSession, + const NamespaceString& ns, + const AggregateCommand& request, + bool isMongos); + +// Checks if this connection has the privileges necessary to create 'ns' with the options +// supplied in 'cmdObj' either directly on mongoD or via mongoS. +Status checkAuthForCreate(AuthorizationSession* authSession, + const CreateCommand& cmd, + bool isMongos); + +// Checks if this connection has the privileges necessary to modify 'ns' with the options +// supplied in 'cmdObj' either directly on mongoD or via mongoS. +Status checkAuthForCollMod(AuthorizationSession* authSession, + const NamespaceString& ns, + const BSONObj& cmdObj, + bool isMongos); + +} // namespace mongo::auth diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index a64b4ed8fbf..23269084d1b 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -32,7 +32,6 @@ #include <memory> #include "mongo/base/status.h" -#include "mongo/bson/mutable/document.h" #include "mongo/config.h" #include "mongo/crypto/mechanism_scram.h" #include "mongo/crypto/sha1_block.h" diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index bd4a4f4c1f3..4f2084e5010 100644 --- a/src/mongo/db/auth/authorization_session.h +++ b/src/mongo/db/auth/authorization_session.h @@ -44,8 +44,6 @@ #include "mongo/db/commands/create_gen.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" -#include "mongo/db/ops/write_ops_parsers.h" -#include "mongo/db/pipeline/aggregate_command_gen.h" namespace mongo { @@ -154,6 +152,9 @@ public: // multiple users are authenticated, this method will throw an exception. virtual User* getSingleUser() = 0; + // Is auth disabled? Returns true if auth is disabled. + virtual bool shouldIgnoreAuthChecks() = 0; + // Is authenticated as at least one user. virtual bool isAuthenticated() = 0; @@ -181,64 +182,6 @@ public: // into a state where the first user can be created. virtual PrivilegeVector getDefaultPrivileges() = 0; - // Checks if this connection has the privileges necessary to perform a find operation - // on the supplied namespace identifier. - virtual Status checkAuthForFind(const NamespaceString& ns, bool hasTerm) = 0; - - // Checks if this connection has the privileges necessary to perform a getMore operation on - // the identified cursor, supposing that cursor is associated with the supplied namespace - // identifier. - virtual Status checkAuthForGetMore(const NamespaceString& ns, - long long cursorID, - bool hasTerm) = 0; - - // Checks if this connection has the privileges necessary to perform the given update on the - // given namespace. - virtual Status checkAuthForUpdate(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query, - const write_ops::UpdateModification& update, - bool upsert) = 0; - - // Checks if this connection has the privileges necessary to insert to the given namespace. - virtual Status checkAuthForInsert(OperationContext* opCtx, const NamespaceString& ns) = 0; - - // Checks if this connection has the privileges necessary to perform a delete on the given - // namespace. - virtual Status checkAuthForDelete(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query) = 0; - - // Checks if this connection has the privileges necessary to perform a killCursor on - // the identified cursor, supposing that cursor is associated with the supplied namespace - // identifier. - virtual Status checkAuthForKillCursors(const NamespaceString& cursorNss, - UserNameIterator cursorOwner) = 0; - - // Attempts to get the privileges necessary to run the aggregation pipeline specified in - // 'request' on the namespace 'ns' either directly on mongoD or via mongoS. - virtual StatusWith<PrivilegeVector> getPrivilegesForAggregate(const NamespaceString& ns, - const AggregateCommand& request, - bool isMongos) = 0; - - // Checks if this connection has the privileges necessary to create 'ns' with the options - // supplied in 'cmdObj' either directly on mongoD or via mongoS. - virtual Status checkAuthForCreate(const CreateCommand& cmd, bool isMongos) = 0; - - // Checks if this connection has the privileges necessary to modify 'ns' with the options - // supplied in 'cmdObj' either directly on mongoD or via mongoS. - virtual Status checkAuthForCollMod(const NamespaceString& ns, - const BSONObj& cmdObj, - bool isMongos) = 0; - - // Checks if this connection has the privileges necessary to grant the given privilege - // to a role. - virtual Status checkAuthorizedToGrantPrivilege(const Privilege& privilege) = 0; - - // Checks if this connection has the privileges necessary to revoke the given privilege - // from a role. - virtual Status checkAuthorizedToRevokePrivilege(const Privilege& privilege) = 0; - // Checks if the current session is authorized to list the collections in the given // database. If it is, return a privilegeVector containing the privileges used to authorize // this command. @@ -259,26 +202,10 @@ public: // Checks if this connection has the privileges necessary to create a new role virtual bool isAuthorizedToCreateRole(const RoleName& roleName) = 0; - // Utility function for isAuthorizedForActionsOnResource( - // ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole) - virtual bool isAuthorizedToGrantRole(const RoleName& role) = 0; - - // Utility function for isAuthorizedForActionsOnResource( - // ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole) - virtual bool isAuthorizedToRevokeRole(const RoleName& role) = 0; - // Utility function for isAuthorizedToChangeOwnPasswordAsUser and // isAuthorizedToChangeOwnCustomDataAsUser virtual bool isAuthorizedToChangeAsUser(const UserName& userName, ActionType actionType) = 0; - // Returns true if the current session is authenticated as the given user and that user - // is allowed to change his/her own password - virtual bool isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) = 0; - - // Returns true if the current session is authenticated as the given user and that user - // is allowed to change his/her own customData. - virtual bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) = 0; - // Returns true if any of the authenticated users on this session have the given role. // NOTE: this does not refresh any of the users even if they are marked as invalid. virtual bool isAuthenticatedAsUserWithRole(const RoleName& roleName) = 0; diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp index 0f131648506..20ed5d956a6 100644 --- a/src/mongo/db/auth/authorization_session_impl.cpp +++ b/src/mongo/db/auth/authorization_session_impl.cpp @@ -33,6 +33,7 @@ #include "mongo/db/auth/authorization_session_impl.h" +#include <array> #include <string> #include <vector> @@ -43,17 +44,10 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authz_session_external_state.h" #include "mongo/db/auth/privilege.h" -#include "mongo/db/auth/restriction_environment.h" -#include "mongo/db/auth/security_key.h" -#include "mongo/db/auth/user_management_commands_parser.h" #include "mongo/db/bson/dotted_path_support.h" -#include "mongo/db/catalog/document_validation.h" #include "mongo/db/client.h" -#include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" -#include "mongo/db/pipeline/aggregation_request_helper.h" -#include "mongo/db/pipeline/lite_parsed_pipeline.h" #include "mongo/logv2/log.h" #include "mongo/util/assert_util.h" #include "mongo/util/str.h" @@ -62,7 +56,6 @@ namespace mongo { namespace dps = ::mongo::dotted_path_support; using std::vector; - namespace { std::unique_ptr<AuthorizationSession> authorizationSessionCreateImpl( @@ -77,34 +70,6 @@ auto authorizationSessionCreateRegistration = constexpr StringData ADMIN_DBNAME = "admin"_sd; -// Checks if this connection has the privileges necessary to create or modify the view 'viewNs' -// to be a view on 'viewOnNs' with pipeline 'viewPipeline'. Call this function after verifying -// that the user has the 'createCollection' or 'collMod' action, respectively. -Status checkAuthForCreateOrModifyView(AuthorizationSession* authzSession, - const NamespaceString& viewNs, - const NamespaceString& viewOnNs, - const BSONArray& viewPipeline, - bool isMongos) { - // It's safe to allow a user to create or modify a view if they can't read it anyway. - if (!authzSession->isAuthorizedForActionsOnNamespace(viewNs, ActionType::find)) { - return Status::OK(); - } - - auto request = aggregation_request_helper::parseFromBSON( - viewNs, - BSON("aggregate" << viewOnNs.coll() << "pipeline" << viewPipeline << "cursor" << BSONObj() - << "$db" << viewOnNs.db()), - boost::none, - false); - - auto statusWithPrivs = authzSession->getPrivilegesForAggregate(viewOnNs, request, isMongos); - PrivilegeVector privileges = uassertStatusOK(statusWithPrivs); - if (!authzSession->isAuthorizedForPrivileges(privileges)) { - return Status(ErrorCodes::Unauthorized, "unauthorized"); - } - return Status::OK(); -} - } // namespace AuthorizationSessionImpl::AuthorizationSessionImpl( @@ -267,274 +232,6 @@ PrivilegeVector AuthorizationSessionImpl::getDefaultPrivileges() { return defaultPrivileges; } -StatusWith<PrivilegeVector> AuthorizationSessionImpl::getPrivilegesForAggregate( - const NamespaceString& nss, const AggregateCommand& request, bool isMongos) { - if (!nss.isValid()) { - return Status(ErrorCodes::InvalidNamespace, - str::stream() << "Invalid input namespace, " << nss.ns()); - } - - PrivilegeVector privileges; - - // If this connection does not need to be authenticated (for instance, if auth is disabled), - // returns an empty requirements set. - if (_externalState->shouldIgnoreAuthChecks()) { - return privileges; - } - - const auto& pipeline = request.getPipeline(); - - // If the aggregation pipeline is empty, confirm the user is authorized for find on 'nss'. - if (pipeline.empty()) { - Privilege currentPriv = - Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find); - Privilege::addPrivilegeToPrivilegeVector(&privileges, currentPriv); - return privileges; - } - - // If the first stage of the pipeline is not an initial source, the pipeline is implicitly - // reading documents from the underlying collection. The client must be authorized to do so. - auto liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipeline[0]); - if (!liteParsedDocSource->isInitialSource()) { - Privilege currentPriv = - Privilege(ResourcePattern::forExactNamespace(nss), ActionType::find); - Privilege::addPrivilegeToPrivilegeVector(&privileges, currentPriv); - } - - // Confirm privileges for the pipeline. - for (auto&& pipelineStage : pipeline) { - liteParsedDocSource = LiteParsedDocumentSource::parse(nss, pipelineStage); - PrivilegeVector currentPrivs = liteParsedDocSource->requiredPrivileges( - isMongos, request.getBypassDocumentValidation().value_or(false)); - Privilege::addPrivilegesToPrivilegeVector(&privileges, currentPrivs); - } - return privileges; -} - -Status AuthorizationSessionImpl::checkAuthForFind(const NamespaceString& ns, bool hasTerm) { - if (MONGO_unlikely(ns.isCommand())) { - return Status(ErrorCodes::InternalError, - str::stream() << "Checking query auth on command namespace " << ns.ns()); - } - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for query on " << ns.ns()); - } - - // Only internal clients (such as other nodes in a replica set) are allowed to use - // the 'term' field in a find operation. Use of this field could trigger changes - // in the receiving server's replication state and should be protected. - if (hasTerm && - !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), - ActionType::internal)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for query with term on " << ns.ns()); - } - - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthForGetMore(const NamespaceString& ns, - long long cursorID, - bool hasTerm) { - // Since users can only getMore their own cursors, we verify that a user either is authenticated - // or does not need to be. - if (!_externalState->shouldIgnoreAuthChecks() && !isAuthenticated()) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for getMore on " << ns.db()); - } - - // Only internal clients (such as other nodes in a replica set) are allowed to use - // the 'term' field in a getMore operation. Use of this field could trigger changes - // in the receiving server's replication state and should be protected. - if (hasTerm && - !isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), - ActionType::internal)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for getMore with term on " << ns.ns()); - } - - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthForInsert(OperationContext* opCtx, - const NamespaceString& ns) { - ActionSet required{ActionType::insert}; - if (DocumentValidationSettings::get(opCtx).isSchemaValidationDisabled()) { - required.addAction(ActionType::bypassDocumentValidation); - } - if (!isAuthorizedForActionsOnNamespace(ns, required)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for insert on " << ns.ns()); - } - - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthForUpdate(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query, - const write_ops::UpdateModification& update, - bool upsert) { - ActionSet required{ActionType::update}; - StringData operationType = "update"_sd; - - if (upsert) { - required.addAction(ActionType::insert); - operationType = "upsert"_sd; - } - - if (DocumentValidationSettings::get(opCtx).isSchemaValidationDisabled()) { - required.addAction(ActionType::bypassDocumentValidation); - } - - if (!isAuthorizedForActionsOnNamespace(ns, required)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized for " << operationType << " on " << ns.ns()); - } - - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthForDelete(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query) { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized to remove from " << ns.ns()); - } - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthForKillCursors(const NamespaceString& ns, - UserNameIterator cursorOwner) { - if (isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), - ActionType::killAnyCursor)) { - return Status::OK(); - } - - if (isCoauthorizedWith(cursorOwner)) { - return Status::OK(); - } - - ResourcePattern target; - if (ns.isListCollectionsCursorNS()) { - target = ResourcePattern::forDatabaseName(ns.db()); - } else { - target = ResourcePattern::forExactNamespace(ns); - } - - if (isAuthorizedForActionsOnResource(target, ActionType::killAnyCursor)) { - return Status::OK(); - } - - return Status(ErrorCodes::Unauthorized, - str::stream() << "not authorized to kill cursor on " << ns.ns()); -} - -Status AuthorizationSessionImpl::checkAuthForCreate(const CreateCommand& cmd, bool isMongos) { - auto ns = cmd.getNamespace(); - if (cmd.getCapped() && !isAuthorizedForActionsOnNamespace(ns, ActionType::convertToCapped)) { - return {ErrorCodes::Unauthorized, "unauthorized"}; - } - - const bool hasCreateCollectionAction = - isAuthorizedForActionsOnNamespace(ns, ActionType::createCollection); - - // If attempting to create a view, check for additional required privileges. - if (auto optViewOn = cmd.getViewOn()) { - // You need the createCollection action on this namespace; the insert action is not - // sufficient. - if (!hasCreateCollectionAction) { - return {ErrorCodes::Unauthorized, "unauthorized"}; - } - - // Parse the viewOn namespace and the pipeline. If no pipeline was specified, use the empty - // pipeline. - NamespaceString viewOnNs(ns.db(), optViewOn.get()); - auto pipeline = cmd.getPipeline().get_value_or(std::vector<BSONObj>()); - BSONArrayBuilder pipelineArray; - for (const auto& stage : pipeline) { - pipelineArray.append(stage); - } - return checkAuthForCreateOrModifyView(this, ns, viewOnNs, pipelineArray.arr(), isMongos); - } - - // To create a regular collection, ActionType::createCollection or ActionType::insert are - // both acceptable. - if (hasCreateCollectionAction || isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) { - return Status::OK(); - } - - return {ErrorCodes::Unauthorized, "unauthorized"}; -} - -Status AuthorizationSessionImpl::checkAuthForCollMod(const NamespaceString& ns, - const BSONObj& cmdObj, - bool isMongos) { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::collMod)) { - return Status(ErrorCodes::Unauthorized, "unauthorized"); - } - - // Check for additional required privileges if attempting to modify a view. When auth is - // enabled, users must specify both "viewOn" and "pipeline" together. This prevents a user from - // exposing more information in the original underlying namespace by only changing "pipeline", - // or looking up more information via the original pipeline by only changing "viewOn". - const bool hasViewOn = cmdObj.hasField("viewOn"); - const bool hasPipeline = cmdObj.hasField("pipeline"); - if (hasViewOn != hasPipeline) { - return Status( - ErrorCodes::InvalidOptions, - "Must specify both 'viewOn' and 'pipeline' when modifying a view and auth is enabled"); - } - if (hasViewOn) { - NamespaceString viewOnNs(ns.db(), cmdObj["viewOn"].checkAndGetStringData()); - auto viewPipeline = BSONArray(cmdObj["pipeline"].Obj()); - return checkAuthForCreateOrModifyView(this, ns, viewOnNs, viewPipeline, isMongos); - } - - return Status::OK(); -} - -Status AuthorizationSessionImpl::checkAuthorizedToGrantPrivilege(const Privilege& privilege) { - const ResourcePattern& resource = privilege.getResourcePattern(); - if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { - if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(resource.databaseToMatch()), - ActionType::grantRole)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "Not authorized to grant privileges on the " - << resource.databaseToMatch() << "database"); - } - } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"), - ActionType::grantRole)) { - return Status(ErrorCodes::Unauthorized, - "To grant privileges affecting multiple databases or the cluster," - " must be authorized to grant roles from the admin database"); - } - return Status::OK(); -} - - -Status AuthorizationSessionImpl::checkAuthorizedToRevokePrivilege(const Privilege& privilege) { - const ResourcePattern& resource = privilege.getResourcePattern(); - if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { - if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(resource.databaseToMatch()), - ActionType::revokeRole)) { - return Status(ErrorCodes::Unauthorized, - str::stream() << "Not authorized to revoke privileges on the " - << resource.databaseToMatch() << "database"); - } - } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"), - ActionType::revokeRole)) { - return Status(ErrorCodes::Unauthorized, - "To revoke privileges affecting multiple databases or the cluster," - " must be authorized to revoke roles from the admin database"); - } - return Status::OK(); -} - bool AuthorizationSessionImpl::isAuthorizedToParseNamespaceElement(const BSONElement& element) { const bool isUUID = element.type() == BinData && element.binDataType() == BinDataType::newUUID; @@ -586,16 +283,6 @@ bool AuthorizationSessionImpl::isAuthorizedToCreateRole(const RoleName& roleName return false; } -bool AuthorizationSessionImpl::isAuthorizedToGrantRole(const RoleName& role) { - return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()), - ActionType::grantRole); -} - -bool AuthorizationSessionImpl::isAuthorizedToRevokeRole(const RoleName& role) { - return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()), - ActionType::revokeRole); -} - bool AuthorizationSessionImpl::isAuthorizedForPrivilege(const Privilege& privilege) { if (_externalState->shouldIgnoreAuthChecks()) return true; @@ -717,16 +404,6 @@ bool AuthorizationSessionImpl::isAuthorizedToChangeAsUser(const UserName& userNa return actions.contains(actionType); } -bool AuthorizationSessionImpl::isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) { - return AuthorizationSessionImpl::isAuthorizedToChangeAsUser(userName, - ActionType::changeOwnPassword); -} - -bool AuthorizationSessionImpl::isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) { - return AuthorizationSessionImpl::isAuthorizedToChangeAsUser(userName, - ActionType::changeOwnCustomData); -} - StatusWith<PrivilegeVector> AuthorizationSessionImpl::checkAuthorizedToListCollections( StringData dbname, const BSONObj& cmdObj) { if (cmdObj["authorizedCollections"].trueValue() && cmdObj["nameOnly"].trueValue() && @@ -753,6 +430,10 @@ bool AuthorizationSessionImpl::isAuthenticatedAsUserWithRole(const RoleName& rol return false; } +bool AuthorizationSessionImpl::shouldIgnoreAuthChecks() { + return _externalState->shouldIgnoreAuthChecks(); +} + bool AuthorizationSessionImpl::isAuthenticated() { return _authenticatedUsers.begin() != _authenticatedUsers.end(); } diff --git a/src/mongo/db/auth/authorization_session_impl.h b/src/mongo/db/auth/authorization_session_impl.h index df74157aebc..598c05d5239 100644 --- a/src/mongo/db/auth/authorization_session_impl.h +++ b/src/mongo/db/auth/authorization_session_impl.h @@ -30,7 +30,6 @@ #pragma once #include <memory> -#include <string> #include <vector> #include "mongo/base/status.h" @@ -42,7 +41,6 @@ #include "mongo/db/auth/user_name.h" #include "mongo/db/auth/user_set.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/pipeline/aggregate_command_gen.h" namespace mongo { @@ -80,6 +78,8 @@ public: User* lookupUser(const UserName& name) override; + bool shouldIgnoreAuthChecks() override; + bool isAuthenticated() override; User* getSingleUser() override; @@ -96,44 +96,9 @@ public: PrivilegeVector getDefaultPrivileges() override; - Status checkAuthForFind(const NamespaceString& ns, bool hasTerm) override; - - Status checkAuthForGetMore(const NamespaceString& ns, - long long cursorID, - bool hasTerm) override; - - Status checkAuthForUpdate(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query, - const write_ops::UpdateModification& update, - bool upsert) override; - - Status checkAuthForInsert(OperationContext* opCtx, const NamespaceString& ns) override; - - Status checkAuthForDelete(OperationContext* opCtx, - const NamespaceString& ns, - const BSONObj& query) override; - - Status checkAuthForKillCursors(const NamespaceString& cursorNss, - UserNameIterator cursorOwner) override; - - StatusWith<PrivilegeVector> getPrivilegesForAggregate(const NamespaceString& ns, - const AggregateCommand& request, - bool isMongos) override; - - Status checkAuthForCreate(const CreateCommand& cmd, bool isMongos) override; - - Status checkAuthForCollMod(const NamespaceString& ns, - const BSONObj& cmdObj, - bool isMongos) override; - StatusWith<PrivilegeVector> checkAuthorizedToListCollections(StringData dbname, const BSONObj& cmdObj) override; - Status checkAuthorizedToGrantPrivilege(const Privilege& privilege) override; - - Status checkAuthorizedToRevokePrivilege(const Privilege& privilege) override; - bool isUsingLocalhostBypass() override; bool isAuthorizedToParseNamespaceElement(const BSONElement& elem) override; @@ -142,16 +107,8 @@ public: bool isAuthorizedToCreateRole(const RoleName& roleName) override; - bool isAuthorizedToGrantRole(const RoleName& role) override; - - bool isAuthorizedToRevokeRole(const RoleName& role) override; - bool isAuthorizedToChangeAsUser(const UserName& userName, ActionType actionType) override; - bool isAuthorizedToChangeOwnPasswordAsUser(const UserName& userName) override; - - bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName& userName) override; - bool isAuthenticatedAsUserWithRole(const RoleName& roleName) override; bool isAuthorizedForPrivilege(const Privilege& privilege) override; diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 994c82850c0..517117dd298 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -37,6 +37,7 @@ #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_manager_impl.h" #include "mongo/db/auth/authorization_session_for_test.h" #include "mongo/db/auth/authz_manager_external_state_mock.h" @@ -599,8 +600,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateEmptyPipelineWithoutFindAction) testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << BSONArray() << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -611,8 +612,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateEmptyPipelineWithFindAction) { testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << BSONArray() << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -627,8 +628,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateWithoutFindActionIfFirstStageNot testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -641,8 +642,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateWithFindActionIfPipelineContains testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -654,8 +655,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCollStatsWithoutCollStatsAction) testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -667,8 +668,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateCollStatsWithCollStatsAction) { testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -680,8 +681,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateIndexStatsWithoutIndexStatsActio testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -693,8 +694,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateIndexStatsWithIndexStatsAction) { testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -706,8 +707,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersFalseWithoutInprog testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -719,8 +720,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersFalseWithoutInp testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -740,8 +741,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersFalseIfNotAuthe BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -753,8 +754,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInpr testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -766,8 +767,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInpr testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -780,8 +781,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActi testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -794,8 +795,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActi testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -808,8 +809,8 @@ TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMon testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -822,8 +823,8 @@ TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMon testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -836,9 +837,10 @@ TEST_F(AuthorizationSessionTest, AddPrivilegesForStageFailsIfOutNamespaceIsNotVa testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - ASSERT_THROWS_CODE(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false), - AssertionException, - ErrorCodes::InvalidNamespace); + ASSERT_THROWS_CODE( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false), + AssertionException, + ErrorCodes::InvalidNamespace); } TEST_F(AuthorizationSessionTest, CannotAggregateOutWithoutInsertAndRemoveOnTargetNamespace) { @@ -850,8 +852,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateOutWithoutInsertAndRemoveOnTarge testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); // We have insert but not remove on the $out namespace. @@ -875,8 +877,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateOutWithInsertAndRemoveOnTargetNames testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); auto aggNoBypassDocumentValidationReq = @@ -886,8 +888,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateOutWithInsertAndRemoveOnTargetNames << "bypassDocumentValidation" << false << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - privileges = uassertStatusOK(authzSession->getPrivilegesForAggregate( - testFooNss, aggNoBypassDocumentValidationReq, false)); + privileges = uassertStatusOK(auth::getPrivilegesForAggregate( + authzSession.get(), testFooNss, aggNoBypassDocumentValidationReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -902,8 +904,8 @@ TEST_F(AuthorizationSessionTest, testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "bypassDocumentValidation" << true << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -920,8 +922,8 @@ TEST_F(AuthorizationSessionTest, testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "bypassDocumentValidation" << true << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -933,8 +935,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnJoinedNamespa testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -947,8 +949,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnJoinedNamespace) { testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -964,8 +966,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnNestedJoinedN testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -981,8 +983,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnNestedJoinedNamespa testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -1026,8 +1028,8 @@ TEST_F(AuthorizationSessionTest, CheckAuthForAggregateWithDeeplyNestedLookup) { auto aggReq = uassertStatusOK( aggregation_request_helper::parseFromBSONForTests(testFooNss, cmdBuilder.obj())); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -1040,8 +1042,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateGraphLookupWithoutFindOnJoinedNa testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -1054,8 +1056,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateGraphLookupWithFindOnJoinedNamespac testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } @@ -1071,8 +1073,8 @@ TEST_F(AuthorizationSessionTest, testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, false)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, false)); ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges)); // We have find on the $lookup namespace but not on the $graphLookup namespace. @@ -1100,8 +1102,8 @@ TEST_F(AuthorizationSessionTest, testFooNss, BSON("aggregate" << testFooNss.coll() << "pipeline" << pipeline << "cursor" << BSONObj() << "$db" << testFooNss.db()))); - PrivilegeVector privileges = - uassertStatusOK(authzSession->getPrivilegesForAggregate(testFooNss, aggReq, true)); + PrivilegeVector privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(authzSession.get(), testFooNss, aggReq, true)); ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges)); } diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp index 966a8271517..c471dffd63f 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -34,9 +34,6 @@ #include "mongo/db/auth/authz_manager_external_state_local.h" #include "mongo/base/status.h" -#include "mongo/bson/mutable/algorithm.h" -#include "mongo/bson/mutable/document.h" -#include "mongo/bson/mutable/element.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/address_restriction.h" #include "mongo/db/auth/auth_options_gen.h" diff --git a/src/mongo/db/auth/authz_manager_external_state_local.h b/src/mongo/db/auth/authz_manager_external_state_local.h index 68d24ebed79..629bdfe3340 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.h +++ b/src/mongo/db/auth/authz_manager_external_state_local.h @@ -42,10 +42,6 @@ namespace mongo { -namespace mutablebson { -class Document; -} // namespace mutablebson - /** * Common implementation of AuthzManagerExternalState for systems where role * and user information are stored locally. diff --git a/src/mongo/db/auth/builtin_roles_test.cpp b/src/mongo/db/auth/builtin_roles_test.cpp index e58ca9b2bf6..283c7f57df7 100644 --- a/src/mongo/db/auth/builtin_roles_test.cpp +++ b/src/mongo/db/auth/builtin_roles_test.cpp @@ -33,7 +33,6 @@ #include <algorithm> -#include "mongo/bson/mutable/document.h" #include "mongo/db/auth/builtin_roles.h" #include "mongo/unittest/unittest.h" #include "mongo/util/sequence_util.h" diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp index 7e4bd3766c8..d8df2909511 100644 --- a/src/mongo/db/auth/sasl_authentication_session_test.cpp +++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp @@ -30,9 +30,6 @@ #include <string> #include <vector> -#include "mongo/bson/mutable/algorithm.h" -#include "mongo/bson/mutable/document.h" -#include "mongo/bson/mutable/element.h" #include "mongo/client/sasl_client_session.h" #include "mongo/crypto/mechanism_scram.h" #include "mongo/db/auth/authorization_manager.h" diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp index 30244aac85d..25f09916a51 100644 --- a/src/mongo/db/auth/sasl_commands.cpp +++ b/src/mongo/db/auth/sasl_commands.cpp @@ -36,8 +36,6 @@ #include "mongo/base/init.h" #include "mongo/base/status.h" #include "mongo/base/string_data.h" -#include "mongo/bson/mutable/algorithm.h" -#include "mongo/bson/mutable/document.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/client/authenticate.h" #include "mongo/client/sasl_client_authenticate.h" diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index 8ca97e3ae2a..1347c0af83c 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" @@ -125,10 +126,10 @@ public: } const auto hasTerm = false; - return authSession->checkAuthForFind( - CollectionCatalog::get(opCtx)->resolveNamespaceStringOrUUID( - opCtx, CommandHelpers::parseNsOrUUID(dbname, cmdObj)), - hasTerm); + return auth::checkAuthForFind(authSession, + CollectionCatalog::get(opCtx)->resolveNamespaceStringOrUUID( + opCtx, CommandHelpers::parseNsOrUUID(dbname, cmdObj)), + hasTerm); } Status explain(OperationContext* opCtx, diff --git a/src/mongo/db/commands/dbcheck.cpp b/src/mongo/db/commands/dbcheck.cpp index a8ff511fe6d..6ff08ec7711 100644 --- a/src/mongo/db/commands/dbcheck.cpp +++ b/src/mongo/db/commands/dbcheck.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/catalog/database.h" @@ -522,14 +523,15 @@ public: const NamespaceString nss(parseNs(dbname, cmdObj)); // First, check that we can read this collection. - Status status = AuthorizationSession::get(client)->checkAuthForFind(nss, false); + auto authSession = AuthorizationSession::get(client); + Status status = auth::checkAuthForFind(authSession, nss, false); if (!status.isOK()) { return status; } // Then check that we can read the health log. - return AuthorizationSession::get(client)->checkAuthForFind(HealthLog::nss, false); + return auth::checkAuthForFind(authSession, HealthLog::nss, false); } virtual bool run(OperationContext* opCtx, diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 86b13499dda..bdb83f66653 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -41,6 +41,7 @@ #include "mongo/db/audit.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/user_management_commands_parser.h" @@ -316,8 +317,8 @@ public: } void doCheckAuthorization(OperationContext* opCtx) const final { - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForCreate(request(), false)); + uassertStatusOK(auth::checkAuthForCreate( + AuthorizationSession::get(opCtx->getClient()), request(), false)); } NamespaceString ns() const final { @@ -745,7 +746,7 @@ public: const std::string& dbname, const BSONObj& cmdObj) const { const NamespaceString nss(parseNs(dbname, cmdObj)); - return AuthorizationSession::get(client)->checkAuthForCollMod(nss, cmdObj, false); + return auth::checkAuthForCollMod(AuthorizationSession::get(client), nss, cmdObj, false); } bool runWithRequestParser(OperationContext* opCtx, diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 738db9ffb2c..2c01df647bc 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -35,6 +35,7 @@ #include <string> #include <vector> +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/client.h" @@ -124,10 +125,10 @@ public: } const auto hasTerm = false; - return authSession->checkAuthForFind( - CollectionCatalog::get(opCtx)->resolveNamespaceStringOrUUID( - opCtx, CommandHelpers::parseNsOrUUID(dbname, cmdObj)), - hasTerm); + return auth::checkAuthForFind(authSession, + CollectionCatalog::get(opCtx)->resolveNamespaceStringOrUUID( + opCtx, CommandHelpers::parseNsOrUUID(dbname, cmdObj)), + hasTerm); } Status explain(OperationContext* opCtx, diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index a26fbf4f343..2b7665c8638 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" @@ -231,7 +232,8 @@ public: authSession->isAuthorizedToParseNamespaceElement(_request.body.firstElement())); const auto hasTerm = _request.body.hasField(kTermField); - uassertStatusOK(authSession->checkAuthForFind( + uassertStatusOK(auth::checkAuthForFind( + authSession, CollectionCatalog::get(opCtx)->resolveNamespaceStringOrUUID( opCtx, CommandHelpers::parseNsOrUUID(_dbName, _request.body)), hasTerm)); diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 53ead6d1e12..50c742a612d 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -34,6 +34,7 @@ #include <memory> #include <string> +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/client.h" @@ -283,8 +284,8 @@ public: } void doCheckAuthorization(OperationContext* opCtx) const override { - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForGetMore(_request.nss, + uassertStatusOK(auth::checkAuthForGetMore(AuthorizationSession::get(opCtx->getClient()), + _request.nss, _request.cursorid, _request.term.is_initialized())); } diff --git a/src/mongo/db/commands/oplog_application_checks.cpp b/src/mongo/db/commands/oplog_application_checks.cpp index b6651773d80..d85579c1330 100644 --- a/src/mongo/db/commands/oplog_application_checks.cpp +++ b/src/mongo/db/commands/oplog_application_checks.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" #include "mongo/bson/util/bson_check.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection_catalog.h" #include "mongo/db/catalog/document_validation.h" @@ -105,7 +106,7 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC } if (opType == "i"_sd) { - return authSession->checkAuthForInsert(opCtx, ns); + return auth::checkAuthForInsert(authSession, opCtx, ns); } else if (opType == "u"_sd) { BSONElement o2Elem = oplogEntry["o2"]; checkBSONType(BSONType::Object, o2Elem); @@ -119,11 +120,15 @@ Status OplogApplicationChecks::checkOperationAuthorization(OperationContext* opC const bool upsert = b || alwaysUpsert; - return authSession->checkAuthForUpdate( - opCtx, ns, o2, write_ops::UpdateModification::parseFromOplogEntry(o), upsert); + return auth::checkAuthForUpdate(authSession, + opCtx, + ns, + o2, + write_ops::UpdateModification::parseFromOplogEntry(o), + upsert); } else if (opType == "d"_sd) { - return authSession->checkAuthForDelete(opCtx, ns, o); + return auth::checkAuthForDelete(authSession, opCtx, ns, o); } else if (opType == "db"_sd) { // It seems that 'db' isn't used anymore. Require all actions to prevent casual use. ActionSet allActions; diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index 39e25705af1..5cd32640290 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/run_aggregate.h" @@ -78,10 +79,11 @@ public: explainVerbosity, APIParameters::get(opCtx).getAPIStrict().value_or(false)); - auto privileges = - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->getPrivilegesForAggregate( - aggregationRequest.getNamespace(), aggregationRequest, false)); + auto privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(AuthorizationSession::get(opCtx->getClient()), + aggregationRequest.getNamespace(), + aggregationRequest, + false)); return std::make_unique<Invocation>( this, opMsgRequest, std::move(aggregationRequest), std::move(privileges)); diff --git a/src/mongo/db/commands/user_management_commands_common.cpp b/src/mongo/db/commands/user_management_commands_common.cpp index 826d70d3eba..0bc6f32cf49 100644 --- a/src/mongo/db/commands/user_management_commands_common.cpp +++ b/src/mongo/db/commands/user_management_commands_common.cpp @@ -50,6 +50,29 @@ namespace mongo { namespace auth { +namespace { + +Status checkAuthorizedToGrantPrivilege(AuthorizationSession* authzSession, + const Privilege& privilege) { + const ResourcePattern& resource = privilege.getResourcePattern(); + if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { + if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(resource.databaseToMatch()), + ActionType::grantRole)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "Not authorized to grant privileges on the " + << resource.databaseToMatch() << "database"); + } + } else if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName("admin"), ActionType::grantRole)) { + return Status(ErrorCodes::Unauthorized, + "To grant privileges affecting multiple databases or the cluster," + " must be authorized to grant roles from the admin database"); + } + return Status::OK(); +} + +} // namespace std::vector<RoleName> resolveRoleNames(const std::vector<RoleNameOrString>& possibleRoles, StringData dbname) { @@ -64,7 +87,8 @@ std::vector<RoleName> resolveRoleNames(const std::vector<RoleNameOrString>& poss Status checkAuthorizedToGrantRoles(AuthorizationSession* authzSession, const std::vector<RoleName>& roles) { for (size_t i = 0; i < roles.size(); ++i) { - if (!authzSession->isAuthorizedToGrantRole(roles[i])) { + if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(roles[i].getDB()), ActionType::grantRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to grant role: " << roles[i].getFullName()); @@ -77,7 +101,7 @@ Status checkAuthorizedToGrantRoles(AuthorizationSession* authzSession, Status checkAuthorizedToGrantPrivileges(AuthorizationSession* authzSession, const PrivilegeVector& privileges) { for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) { - Status status = authzSession->checkAuthorizedToGrantPrivilege(*it); + Status status = checkAuthorizedToGrantPrivilege(authzSession, *it); if (!status.isOK()) { return status; } @@ -89,7 +113,8 @@ Status checkAuthorizedToGrantPrivileges(AuthorizationSession* authzSession, Status checkAuthorizedToRevokeRoles(AuthorizationSession* authzSession, const std::vector<RoleName>& roles) { for (size_t i = 0; i < roles.size(); ++i) { - if (!authzSession->isAuthorizedToRevokeRole(roles[i])) { + if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(roles[i].getDB()), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to revoke role: " << roles[i].getFullName()); @@ -98,10 +123,31 @@ Status checkAuthorizedToRevokeRoles(AuthorizationSession* authzSession, return Status::OK(); } + +Status checkAuthorizedToRevokePrivilege(AuthorizationSession* authzSession, + const Privilege& privilege) { + const ResourcePattern& resource = privilege.getResourcePattern(); + if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { + if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName(resource.databaseToMatch()), + ActionType::revokeRole)) { + return Status(ErrorCodes::Unauthorized, + str::stream() << "Not authorized to revoke privileges on the " + << resource.databaseToMatch() << "database"); + } + } else if (!authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forDatabaseName("admin"), ActionType::revokeRole)) { + return Status(ErrorCodes::Unauthorized, + "To revoke privileges affecting multiple databases or the cluster," + " must be authorized to revoke roles from the admin database"); + } + return Status::OK(); +} + Status checkAuthorizedToRevokePrivileges(AuthorizationSession* authzSession, const PrivilegeVector& privileges) { for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) { - Status status = authzSession->checkAuthorizedToRevokePrivilege(*it); + Status status = checkAuthorizedToRevokePrivilege(authzSession, *it); if (!status.isOK()) { return status; } @@ -124,6 +170,16 @@ Status checkAuthorizedToSetRestrictions(AuthorizationSession* authzSession, return Status::OK(); } +bool isAuthorizedToChangeOwnPasswordAsUser(AuthorizationSession* authzSession, + const UserName& userName) { + return authzSession->isAuthorizedToChangeAsUser(userName, ActionType::changeOwnPassword); +} + +bool isAuthorizedToChangeOwnCustomDataAsUser(AuthorizationSession* authzSession, + const UserName& userName) { + return authzSession->isAuthorizedToChangeAsUser(userName, ActionType::changeOwnCustomData); +} + void checkAuthForTypedCommand(Client* client, const CreateUserCommand& request) { const auto& dbname = request.getDbName(); auto* as = AuthorizationSession::get(client); @@ -148,7 +204,7 @@ void checkAuthForTypedCommand(Client* client, const UpdateUserCommand& request) uassert( ErrorCodes::Unauthorized, str::stream() << "Not authorized to change password of user: " << userName.getFullName(), - (request.getPwd() == boost::none) || as->isAuthorizedToChangeOwnPasswordAsUser(userName) || + (request.getPwd() == boost::none) || isAuthorizedToChangeOwnPasswordAsUser(as, userName) || as->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname), ActionType::changePassword)); @@ -156,7 +212,7 @@ void checkAuthForTypedCommand(Client* client, const UpdateUserCommand& request) str::stream() << "Not authorized to change customData of user: " << userName.getFullName(), (request.getCustomData() == boost::none) || - as->isAuthorizedToChangeOwnCustomDataAsUser(userName) || + isAuthorizedToChangeOwnCustomDataAsUser(as, userName) || as->isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(dbname), ActionType::changeCustomData)); diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp index b2448100ded..b5b72bfe2c2 100644 --- a/src/mongo/db/cursor_manager.cpp +++ b/src/mongo/db/cursor_manager.cpp @@ -38,6 +38,7 @@ #include "mongo/base/data_cursor.h" #include "mongo/base/init.h" #include "mongo/db/audit.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" @@ -494,7 +495,7 @@ Status CursorManager::checkAuthForKillCursors(OperationContext* opCtx, CursorId // after the cursor's creation. We're guaranteed that the cursor won't get destroyed while we're // reading from it because we hold the partition's lock. AuthorizationSession* as = AuthorizationSession::get(opCtx->getClient()); - return as->checkAuthForKillCursors(cursor->nss(), cursor->getAuthenticatedUsers()); + return auth::checkAuthForKillCursors(as, cursor->nss(), cursor->getAuthenticatedUsers()); } } // namespace mongo diff --git a/src/mongo/db/pipeline/process_interface/SConscript b/src/mongo/db/pipeline/process_interface/SConscript index eeeb497feb2..4ead2683ec0 100644 --- a/src/mongo/db/pipeline/process_interface/SConscript +++ b/src/mongo/db/pipeline/process_interface/SConscript @@ -116,6 +116,7 @@ env.CppUnitTest( 'standalone_process_interface_test.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/auth/authmocks', '$BUILD_DIR/mongo/db/query/query_test_service_context', '$BUILD_DIR/mongo/db/service_context_test_fixture', '$BUILD_DIR/mongo/db/vector_clock_mongod', diff --git a/src/mongo/db/run_op_kill_cursors.cpp b/src/mongo/db/run_op_kill_cursors.cpp index d9a42c7f7d8..794a3a819e9 100644 --- a/src/mongo/db/run_op_kill_cursors.cpp +++ b/src/mongo/db/run_op_kill_cursors.cpp @@ -33,6 +33,7 @@ #include "mongo/base/data_cursor.h" #include "mongo/db/audit.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/cursor_id.h" #include "mongo/db/cursor_manager.h" @@ -68,7 +69,7 @@ bool killCursorIfAuthorized(OperationContext* opCtx, CursorId id) { AuthorizationSession* as = AuthorizationSession::get(opCtx->getClient()); auto cursorOwner = pin.getValue().getCursor()->getAuthenticatedUsers(); - auto authStatus = as->checkAuthForKillCursors(nss, cursorOwner); + auto authStatus = auth::checkAuthForKillCursors(as, nss, cursorOwner); if (!authStatus.isOK()) { audit::logKillCursorsAuthzCheck(opCtx->getClient(), nss, id, authStatus.code()); return false; diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index 99d5538df5e..e918fb3d592 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -40,6 +40,7 @@ #include "mongo/bson/util/bson_extract.h" #include "mongo/client/server_discovery_monitor.h" #include "mongo/db/audit.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/impersonation_session.h" #include "mongo/db/client.h" @@ -1893,7 +1894,7 @@ DbResponse receivedQuery(OperationContext* opCtx, try { Client* client = opCtx->getClient(); - Status status = AuthorizationSession::get(client)->checkAuthForFind(nss, false); + Status status = auth::checkAuthForFind(AuthorizationSession::get(client), nss, false); audit::logQueryAuthzCheck(client, nss, q.query, status.code()); uassertStatusOK(status); @@ -1955,8 +1956,8 @@ void receivedInsert(OperationContext* opCtx, const NamespaceString& nsString, co invariant(insertOp.getNamespace() == nsString); for (const auto& obj : insertOp.getDocuments()) { - Status status = - AuthorizationSession::get(opCtx->getClient())->checkAuthForInsert(opCtx, nsString); + Status status = auth::checkAuthForInsert( + AuthorizationSession::get(opCtx->getClient()), opCtx, nsString); audit::logInsertAuthzCheck(opCtx->getClient(), nsString, obj, status.code()); uassertStatusOK(status); } @@ -1969,8 +1970,8 @@ void receivedUpdate(OperationContext* opCtx, const NamespaceString& nsString, co auto& singleUpdate = updateOp.getUpdates()[0]; invariant(updateOp.getNamespace() == nsString); - Status status = AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForUpdate(opCtx, + Status status = auth::checkAuthForUpdate(AuthorizationSession::get(opCtx->getClient()), + opCtx, nsString, singleUpdate.getQ(), singleUpdate.getU(), @@ -1993,8 +1994,8 @@ void receivedDelete(OperationContext* opCtx, const NamespaceString& nsString, co auto& singleDelete = deleteOp.getDeletes()[0]; invariant(deleteOp.getNamespace() == nsString); - Status status = AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForDelete(opCtx, nsString, singleDelete.getQ()); + Status status = auth::checkAuthForDelete( + AuthorizationSession::get(opCtx->getClient()), opCtx, nsString, singleDelete.getQ()); audit::logDeleteAuthzCheck(opCtx->getClient(), nsString, singleDelete.getQ(), status.code()); uassertStatusOK(status); @@ -2033,8 +2034,8 @@ DbResponse receivedGetMore(OperationContext* opCtx, str::stream() << "Invalid ns [" << ns << "]", nsString.isValid()); - Status status = AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForGetMore(nsString, cursorid, false); + Status status = auth::checkAuthForGetMore( + AuthorizationSession::get(opCtx->getClient()), nsString, cursorid, false); audit::logGetMoreAuthzCheck(opCtx->getClient(), nsString, cursorid, status.code()); uassertStatusOK(status); diff --git a/src/mongo/embedded/embedded_auth_session.cpp b/src/mongo/embedded/embedded_auth_session.cpp index f812078f835..17cdb5a3610 100644 --- a/src/mongo/embedded/embedded_auth_session.cpp +++ b/src/mongo/embedded/embedded_auth_session.cpp @@ -80,6 +80,10 @@ public: UASSERT_NOT_IMPLEMENTED; } + bool shouldIgnoreAuthChecks() override { + return true; + } + bool isAuthenticated() override { // It should always be okay to check whether you're authenticated, but on embedded // it should always return false @@ -110,56 +114,6 @@ public: UASSERT_NOT_IMPLEMENTED; } - Status checkAuthForFind(const NamespaceString&, bool) override { - return Status::OK(); - } - - Status checkAuthForGetMore(const NamespaceString&, long long, bool) override { - return Status::OK(); - } - - Status checkAuthForUpdate(OperationContext*, - const NamespaceString&, - const BSONObj&, - const write_ops::UpdateModification&, - bool) override { - return Status::OK(); - } - - Status checkAuthForInsert(OperationContext*, const NamespaceString&) override { - return Status::OK(); - } - - Status checkAuthForDelete(OperationContext*, const NamespaceString&, const BSONObj&) override { - return Status::OK(); - } - - Status checkAuthForKillCursors(const NamespaceString&, UserNameIterator) override { - return Status::OK(); - } - - StatusWith<PrivilegeVector> getPrivilegesForAggregate(const NamespaceString&, - const AggregateCommand&, - bool) override { - return PrivilegeVector(); - } - - Status checkAuthForCreate(const CreateCommand&, bool) override { - return Status::OK(); - } - - Status checkAuthForCollMod(const NamespaceString&, const BSONObj&, bool) override { - return Status::OK(); - } - - Status checkAuthorizedToGrantPrivilege(const Privilege&) override { - return Status::OK(); - } - - Status checkAuthorizedToRevokePrivilege(const Privilege&) override { - return Status::OK(); - } - StatusWith<PrivilegeVector> checkAuthorizedToListCollections(StringData, const BSONObj&) override { return PrivilegeVector(); @@ -181,26 +135,10 @@ public: return true; } - bool isAuthorizedToGrantRole(const RoleName&) override { - return true; - } - - bool isAuthorizedToRevokeRole(const RoleName&) override { - return true; - } - bool isAuthorizedToChangeAsUser(const UserName&, ActionType) override { return true; } - bool isAuthorizedToChangeOwnPasswordAsUser(const UserName&) override { - return true; - } - - bool isAuthorizedToChangeOwnCustomDataAsUser(const UserName&) override { - return true; - } - bool isAuthenticatedAsUserWithRole(const RoleName&) override { return true; } diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 84cb0f4d9f2..275ae43565a 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -104,6 +104,7 @@ env.Library( LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/auth/auth', + '$BUILD_DIR/mongo/db/auth/auth_checks', '$BUILD_DIR/mongo/db/auth/builtin_roles', '$BUILD_DIR/mongo/db/auth/saslauth', '$BUILD_DIR/mongo/db/commands', diff --git a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp index f57881178f6..6cd3124a0b9 100644 --- a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp +++ b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/coll_mod_gen.h" #include "mongo/db/coll_mod_reply_validation.h" @@ -69,7 +70,7 @@ public: const std::string& dbname, const BSONObj& cmdObj) const override { const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); - return AuthorizationSession::get(client)->checkAuthForCollMod(nss, cmdObj, true); + return auth::checkAuthForCollMod(AuthorizationSession::get(client), nss, cmdObj, true); } bool supportsWriteConcern(const BSONObj& cmd) const override { diff --git a/src/mongo/s/commands/cluster_create_cmd.cpp b/src/mongo/s/commands/cluster_create_cmd.cpp index a288fbd8815..8999dd01aba 100644 --- a/src/mongo/s/commands/cluster_create_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/commands/create_gen.h" @@ -37,6 +38,7 @@ #include "mongo/s/cluster_commands_helpers.h" #include "mongo/s/grid.h" + namespace mongo { namespace { @@ -105,8 +107,8 @@ public: } void doCheckAuthorization(OperationContext* opCtx) const final { - uassertStatusOK( - AuthorizationSession::get(opCtx->getClient())->checkAuthForCreate(request(), true)); + uassertStatusOK(auth::checkAuthForCreate( + AuthorizationSession::get(opCtx->getClient()), request(), true)); } CreateCommandReply typedRun(OperationContext* opCtx) final { diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 1199afe30ad..0403314e50b 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -32,6 +32,7 @@ #include <boost/optional.hpp> #include "mongo/client/read_preference.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/matcher/extensions_callback_noop.h" @@ -145,8 +146,8 @@ public: */ void doCheckAuthorization(OperationContext* opCtx) const final { auto hasTerm = _request.body.hasField(kTermField); - uassertStatusOK( - AuthorizationSession::get(opCtx->getClient())->checkAuthForFind(ns(), hasTerm)); + uassertStatusOK(auth::checkAuthForFind( + AuthorizationSession::get(opCtx->getClient()), ns(), hasTerm)); } void explain(OperationContext* opCtx, diff --git a/src/mongo/s/commands/cluster_getmore_cmd.cpp b/src/mongo/s/commands/cluster_getmore_cmd.cpp index 037e278d1e3..a08fd0d3e0a 100644 --- a/src/mongo/s/commands/cluster_getmore_cmd.cpp +++ b/src/mongo/s/commands/cluster_getmore_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/query/cursor_response.h" @@ -90,8 +91,8 @@ public: } void doCheckAuthorization(OperationContext* opCtx) const override { - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->checkAuthForGetMore(_request.nss, + uassertStatusOK(auth::checkAuthForGetMore(AuthorizationSession::get(opCtx->getClient()), + _request.nss, _request.cursorid, _request.term.is_initialized())); } diff --git a/src/mongo/s/commands/cluster_killcursors_cmd.cpp b/src/mongo/s/commands/cluster_killcursors_cmd.cpp index b902dbf5de1..c05ac76d7fb 100644 --- a/src/mongo/s/commands/cluster_killcursors_cmd.cpp +++ b/src/mongo/s/commands/cluster_killcursors_cmd.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands/killcursors_common.h" #include "mongo/s/grid.h" @@ -45,7 +46,7 @@ struct ClusterKillCursorsCmd { CursorId cursorId) { auto const authzSession = AuthorizationSession::get(opCtx->getClient()); auto authChecker = [&authzSession, &nss](UserNameIterator userNames) -> Status { - return authzSession->checkAuthForKillCursors(nss, userNames); + return auth::checkAuthForKillCursors(authzSession, nss, userNames); }; return Grid::get(opCtx)->getCursorManager()->checkAuthForKillCursors( diff --git a/src/mongo/s/commands/cluster_pipeline_cmd.cpp b/src/mongo/s/commands/cluster_pipeline_cmd.cpp index d8adbc4ed5b..8331e1d754b 100644 --- a/src/mongo/s/commands/cluster_pipeline_cmd.cpp +++ b/src/mongo/s/commands/cluster_pipeline_cmd.cpp @@ -32,6 +32,7 @@ #include "mongo/platform/basic.h" #include "mongo/base/status.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/pipeline/aggregate_command_gen.h" @@ -79,10 +80,11 @@ public: explainVerbosity, APIParameters::get(opCtx).getAPIStrict().value_or(false)); - auto privileges = - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->getPrivilegesForAggregate( - aggregationRequest.getNamespace(), aggregationRequest, true)); + auto privileges = uassertStatusOK( + auth::getPrivilegesForAggregate(AuthorizationSession::get(opCtx->getClient()), + aggregationRequest.getNamespace(), + aggregationRequest, + true)); return std::make_unique<Invocation>( this, opMsgRequest, std::move(aggregationRequest), std::move(privileges)); diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index b5f8fd550a1..bb97a416c7d 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -42,6 +42,7 @@ #include "mongo/bson/util/builder.h" #include "mongo/db/audit.h" #include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_checks.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/curop.h" @@ -1061,7 +1062,7 @@ DbResponse Strategy::queryOp(OperationContext* opCtx, const NamespaceString& nss opCtx->setComment(commentField.wrap()); } - Status status = authSession->checkAuthForFind(nss, false); + Status status = auth::checkAuthForFind(authSession, nss, false); audit::logQueryAuthzCheck(client, nss, q.query, status.code()); uassertStatusOK(status); @@ -1382,7 +1383,7 @@ void Strategy::killCursors(OperationContext* opCtx, DbMessage* dbm) { auto authzSession = AuthorizationSession::get(client); auto authChecker = [&authzSession, &nss](UserNameIterator userNames) -> Status { - return authzSession->checkAuthForKillCursors(*nss, userNames); + return auth::checkAuthForKillCursors(authzSession, *nss, userNames); }; auto authzStatus = manager->checkAuthForKillCursors(opCtx, *nss, cursorId, authChecker); audit::logKillCursorsAuthzCheck(client, *nss, cursorId, authzStatus.code()); |