summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/auth/SConscript34
-rw-r--r--src/mongo/db/auth/authorization_checks.cpp318
-rw-r--r--src/mongo/db/auth/authorization_checks.h104
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp1
-rw-r--r--src/mongo/db/auth/authorization_session.h79
-rw-r--r--src/mongo/db/auth/authorization_session_impl.cpp329
-rw-r--r--src/mongo/db/auth/authorization_session_impl.h47
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp132
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp3
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.h4
-rw-r--r--src/mongo/db/auth/builtin_roles_test.cpp1
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp3
-rw-r--r--src/mongo/db/auth/sasl_commands.cpp2
-rw-r--r--src/mongo/db/commands/count_cmd.cpp9
-rw-r--r--src/mongo/db/commands/dbcheck.cpp6
-rw-r--r--src/mongo/db/commands/dbcommands.cpp7
-rw-r--r--src/mongo/db/commands/distinct.cpp9
-rw-r--r--src/mongo/db/commands/find_cmd.cpp4
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp5
-rw-r--r--src/mongo/db/commands/oplog_application_checks.cpp13
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp10
-rw-r--r--src/mongo/db/commands/user_management_commands_common.cpp68
-rw-r--r--src/mongo/db/cursor_manager.cpp3
-rw-r--r--src/mongo/db/pipeline/process_interface/SConscript1
-rw-r--r--src/mongo/db/run_op_kill_cursors.cpp3
-rw-r--r--src/mongo/db/service_entry_point_common.cpp19
-rw-r--r--src/mongo/embedded/embedded_auth_session.cpp70
-rw-r--r--src/mongo/s/commands/SConscript1
-rw-r--r--src/mongo/s/commands/cluster_collection_mod_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_create_cmd.cpp6
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_getmore_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_killcursors_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_pipeline_cmd.cpp10
-rw-r--r--src/mongo/s/commands/strategy.cpp5
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());