summaryrefslogtreecommitdiff
path: root/src/mongo/db/auth
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2021-02-26 12:17:39 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-02-26 21:43:07 +0000
commit977f5f0b3305e87183a567144ef11481cec43872 (patch)
treea05c6f491f1c97b9456032280fc66e615e079637 /src/mongo/db/auth
parentb769da11bca2c4e89d83efd6cd7bb4dbe4560245 (diff)
downloadmongo-977f5f0b3305e87183a567144ef11481cec43872.tar.gz
SERVER-54501 Write AuthorizationContract class
Diffstat (limited to 'src/mongo/db/auth')
-rw-r--r--src/mongo/db/auth/SConscript20
-rw-r--r--src/mongo/db/auth/access_checks.idl1
-rw-r--r--src/mongo/db/auth/action_set.cpp10
-rw-r--r--src/mongo/db/auth/action_set.h9
-rw-r--r--src/mongo/db/auth/authorization_contract.cpp70
-rw-r--r--src/mongo/db/auth/authorization_contract.h103
-rw-r--r--src/mongo/db/auth/authorization_contract_test.cpp169
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp98
-rw-r--r--src/mongo/db/auth/privilege.cpp4
-rw-r--r--src/mongo/db/auth/privilege.h4
-rw-r--r--src/mongo/db/auth/resource_pattern.h9
11 files changed, 437 insertions, 60 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 6a2bb098b93..bf18730cbc8 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -164,6 +164,7 @@ env.Library(
'$BUILD_DIR/mongo/util/net/ssl_types',
'address_restriction',
'auth',
+ 'auth_umc',
'authorization_manager_global',
'authprivilege',
'builtin_roles',
@@ -211,10 +212,25 @@ env.Library(
'action_set.cpp',
'action_type.cpp',
'action_type.idl',
- 'impersonation_session.cpp',
+ 'authorization_contract.cpp',
'privilege.cpp',
'privilege_parser.cpp',
'resource_pattern.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/bson/mutable/mutable_bson',
+ '$BUILD_DIR/mongo/idl/idl_parser',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/common',
+ ],
+)
+
+env.Library(
+ target='auth_umc',
+ source=[
+ 'impersonation_session.cpp',
'user_management_commands_parser.cpp',
],
LIBDEPS=[
@@ -223,6 +239,7 @@ env.Library(
'$BUILD_DIR/mongo/db/common',
'address_restriction',
'auth',
+ 'authprivilege',
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/rpc/metadata_impersonated_user',
@@ -439,6 +456,7 @@ env.CppUnitTest(
source=[
'action_set_test.cpp',
'address_restriction_test.cpp',
+ 'authorization_contract_test.cpp',
'auth_op_observer_test.cpp',
'authorization_manager_test.cpp',
'authorization_session_for_test.cpp',
diff --git a/src/mongo/db/auth/access_checks.idl b/src/mongo/db/auth/access_checks.idl
index 7eae9c8fc3d..cc5b6955cc2 100644
--- a/src/mongo/db/auth/access_checks.idl
+++ b/src/mongo/db/auth/access_checks.idl
@@ -35,3 +35,4 @@ enums:
values:
kIsAuthenticated : "is_authenticated"
kIsCoAuthorized : "is_coauthorized"
+ kIsAuthorizedToParseNamespaceElement : "is_authorized_to_parse_namespace_element"
diff --git a/src/mongo/db/auth/action_set.cpp b/src/mongo/db/auth/action_set.cpp
index 4ebf0ac82e0..4744139df93 100644
--- a/src/mongo/db/auth/action_set.cpp
+++ b/src/mongo/db/auth/action_set.cpp
@@ -45,7 +45,7 @@ ActionSet::ActionSet(std::initializer_list<ActionType> actions) {
}
}
-void ActionSet::addAction(const ActionType& action) {
+void ActionSet::addAction(ActionType action) {
if (action == ActionType::anyAction) {
addAllActions();
return;
@@ -65,7 +65,7 @@ void ActionSet::addAllActions() {
_actions.set();
}
-void ActionSet::removeAction(const ActionType& action) {
+void ActionSet::removeAction(ActionType action) {
_actions.set(static_cast<size_t>(action), false);
_actions.set(static_cast<size_t>(ActionType::anyAction), false);
}
@@ -81,10 +81,14 @@ void ActionSet::removeAllActions() {
_actions.reset();
}
-bool ActionSet::contains(const ActionType& action) const {
+bool ActionSet::contains(ActionType action) const {
return _actions[static_cast<size_t>(action)];
}
+bool ActionSet::contains(const ActionSet& other) const {
+ return (_actions | other._actions) == _actions;
+}
+
bool ActionSet::isSupersetOf(const ActionSet& other) const {
return (_actions & other._actions) == other._actions;
}
diff --git a/src/mongo/db/auth/action_set.h b/src/mongo/db/auth/action_set.h
index 1616506dc35..be64e833cae 100644
--- a/src/mongo/db/auth/action_set.h
+++ b/src/mongo/db/auth/action_set.h
@@ -49,13 +49,13 @@ public:
ActionSet() = default;
ActionSet(std::initializer_list<ActionType> actions);
- void addAction(const ActionType& action);
+ void addAction(ActionType action);
void addAllActionsFromSet(const ActionSet& actionSet);
void addAllActions();
// Removes action from the set. Also removes the "anyAction" action, if present.
// Note: removing the "anyAction" action does *not* remove all other actions.
- void removeAction(const ActionType& action);
+ void removeAction(ActionType action);
void removeAllActionsFromSet(const ActionSet& actionSet);
void removeAllActions();
@@ -67,7 +67,10 @@ public:
return this->_actions == other._actions;
}
- bool contains(const ActionType& action) const;
+ bool contains(ActionType action) const;
+
+ // Returns true if this action set contains the entire other action set
+ bool contains(const ActionSet& other) const;
// Returns true only if this ActionSet contains all the actions present in the 'other'
// ActionSet.
diff --git a/src/mongo/db/auth/authorization_contract.cpp b/src/mongo/db/auth/authorization_contract.cpp
new file mode 100644
index 00000000000..7a0d3985f4a
--- /dev/null
+++ b/src/mongo/db/auth/authorization_contract.cpp
@@ -0,0 +1,70 @@
+/**
+ * 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_contract.h"
+#include "mongo/db/auth/privilege.h"
+
+namespace mongo {
+
+void AuthorizationContract::addAccessCheck(AccessCheckEnum check) {
+ _checks.set(static_cast<size_t>(check), true);
+}
+
+bool AuthorizationContract::hasAccessCheck(AccessCheckEnum check) const {
+ return _checks.test(static_cast<size_t>(check));
+}
+
+void AuthorizationContract::addPrivilege(const Privilege& p) {
+ auto matchType = p.getResourcePattern().matchType();
+
+ _privilegeChecks[static_cast<size_t>(matchType)].addAllActionsFromSet(p.getActions());
+}
+
+bool AuthorizationContract::hasPrivileges(const Privilege& p) const {
+ auto matchType = p.getResourcePattern().matchType();
+
+ return _privilegeChecks[static_cast<size_t>(matchType)].contains(p.getActions());
+}
+
+bool AuthorizationContract::contains(const AuthorizationContract& other) const {
+
+ if ((_checks | other._checks) != _checks) {
+ return false;
+ }
+
+ for (size_t i = 0; i < _privilegeChecks.size(); ++i) {
+ if (!_privilegeChecks[i].contains(other._privilegeChecks[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_contract.h b/src/mongo/db/auth/authorization_contract.h
new file mode 100644
index 00000000000..b5aba515573
--- /dev/null
+++ b/src/mongo/db/auth/authorization_contract.h
@@ -0,0 +1,103 @@
+/**
+ * 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 <array>
+#include <bitset>
+#include <initializer_list>
+
+#include "mongo/db/auth/access_checks_gen.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/privilege.h"
+
+namespace mongo {
+
+/**
+ * Contains an authorization contract which is the set of authorization checks a command is
+ * permitted to make against AuthorizationSession.
+ *
+ * There are two types of authorization checks:
+ * 1. Checks for privileges
+ * 2. Other forms of checks, simply called access check. These are generally boolean functions on
+ * AuthorizationSession that check criteria like isAuthorized().
+ *
+ * This class is a lossy set.
+ * 1. It does not record a count of times a check has been performed.
+ * 2. It does not record which namespace a check is performed against.
+ */
+class AuthorizationContract {
+public:
+ AuthorizationContract() = default;
+
+ template <typename Checks, typename Privileges>
+ AuthorizationContract(const Checks& checks, const Privileges& privileges) {
+ for (const auto check : checks) {
+ addAccessCheck(check);
+ }
+ for (const auto& p : privileges) {
+ addPrivilege(p);
+ }
+ }
+
+ /**
+ * Add a access check to the contract.
+ */
+ void addAccessCheck(AccessCheckEnum check);
+
+ /**
+ * Add a privilege and all actions contained in the privilege to the contract.
+ */
+ void addPrivilege(const Privilege& p);
+
+ /**
+ * Check if the contract contains a given access check.
+ */
+ bool hasAccessCheck(AccessCheckEnum check) const;
+
+ /**
+ * Check if the contract contains a privilege include all actions in the privilege.
+ */
+ bool hasPrivileges(const Privilege& p) const;
+
+ /**
+ * Check if this contract contains all the checks of the other contract.
+ */
+ bool contains(const AuthorizationContract& other) const;
+
+private:
+ // Set of access checks performed
+ std::bitset<kNumAccessCheckEnum> _checks;
+
+ // Set of privileges performed per resource pattern type
+ std::array<ActionSet, kNumMatchTypeEnum> _privilegeChecks;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_contract_test.cpp b/src/mongo/db/auth/authorization_contract_test.cpp
new file mode 100644
index 00000000000..733fe27bb18
--- /dev/null
+++ b/src/mongo/db/auth/authorization_contract_test.cpp
@@ -0,0 +1,169 @@
+/**
+ * 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/access_checks_gen.h"
+#include "mongo/db/auth/authorization_contract.h"
+
+#include "mongo/db/auth/privilege.h"
+#include "mongo/unittest/unittest.h"
+#include <initializer_list>
+
+namespace mongo {
+namespace {
+
+TEST(AuthContractTest, Basic) {
+
+ AuthorizationContract ac;
+ ac.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
+ ac.addAccessCheck(AccessCheckEnum::kIsCoAuthorized);
+
+ ActionSet enableShardingActions;
+ enableShardingActions.addAction(ActionType::enableSharding);
+ enableShardingActions.addAction(ActionType::refineCollectionShardKey);
+ enableShardingActions.addAction(ActionType::reshardCollection);
+ ac.addPrivilege(Privilege(ResourcePattern::forAnyNormalResource(), enableShardingActions));
+
+ ASSERT_TRUE(ac.hasAccessCheck(AccessCheckEnum::kIsAuthenticated));
+ ASSERT_TRUE(ac.hasAccessCheck(AccessCheckEnum::kIsCoAuthorized));
+
+ ASSERT_FALSE(ac.hasAccessCheck(AccessCheckEnum::kIsAuthorizedToParseNamespaceElement));
+
+
+ ASSERT_TRUE(ac.hasPrivileges(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::enableSharding)));
+ ASSERT_TRUE(ac.hasPrivileges(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::refineCollectionShardKey)));
+ ASSERT_TRUE(ac.hasPrivileges(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::reshardCollection)));
+
+ ASSERT_FALSE(
+ ac.hasPrivileges(Privilege(ResourcePattern::forAnyNormalResource(), ActionType::shutdown)));
+ ASSERT_FALSE(ac.hasPrivileges(
+ Privilege(ResourcePattern::forClusterResource(), ActionType::enableSharding)));
+
+
+ ASSERT_TRUE(ac.hasPrivileges(
+ Privilege(ResourcePattern::forAnyNormalResource(), enableShardingActions)));
+
+ ASSERT_TRUE(ac.contains(ac));
+}
+
+TEST(AuthContractTest, SimpleAccessCheck) {
+
+ AuthorizationContract ac;
+ ac.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
+ ac.addAccessCheck(AccessCheckEnum::kIsCoAuthorized);
+
+ AuthorizationContract empty;
+
+ ASSERT_TRUE(ac.contains(empty));
+ ASSERT_FALSE(empty.contains(ac));
+}
+
+TEST(AuthContractTest, DifferentAccessCheck) {
+
+ AuthorizationContract ac1;
+ ac1.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
+ ac1.addAccessCheck(AccessCheckEnum::kIsCoAuthorized);
+
+ AuthorizationContract ac2;
+ ac2.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
+ ac2.addAccessCheck(AccessCheckEnum::kIsAuthorizedToParseNamespaceElement);
+
+ ASSERT_FALSE(ac1.contains(ac2));
+ ASSERT_FALSE(ac2.contains(ac1));
+}
+
+TEST(AuthContractTest, SimplePrivilege) {
+
+ AuthorizationContract ac;
+ ac.addPrivilege(Privilege(ResourcePattern::forAnyNormalResource(), ActionType::enableSharding));
+
+ AuthorizationContract empty;
+
+ ASSERT_TRUE(ac.contains(empty));
+ ASSERT_FALSE(empty.contains(ac));
+}
+
+
+TEST(AuthContractTest, DifferentResoucePattern) {
+
+ AuthorizationContract ac1;
+ ac1.addPrivilege(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::enableSharding));
+
+ AuthorizationContract ac2;
+ ac2.addPrivilege(Privilege(ResourcePattern::forClusterResource(), ActionType::enableSharding));
+
+ ASSERT_FALSE(ac1.contains(ac2));
+ ASSERT_FALSE(ac2.contains(ac1));
+}
+
+
+TEST(AuthContractTest, DifferentActionType) {
+
+ AuthorizationContract ac1;
+ ac1.addPrivilege(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::enableSharding));
+
+ AuthorizationContract ac2;
+ ac2.addPrivilege(
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::grantPrivilegesToRole));
+
+ ASSERT_FALSE(ac1.contains(ac2));
+ ASSERT_FALSE(ac2.contains(ac1));
+}
+
+
+TEST(AuthContractTest, InitializerList) {
+
+ AuthorizationContract ac1;
+ ac1.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
+ ac1.addAccessCheck(AccessCheckEnum::kIsCoAuthorized);
+
+ ActionSet enableShardingActions;
+ enableShardingActions.addAction(ActionType::enableSharding);
+ enableShardingActions.addAction(ActionType::refineCollectionShardKey);
+ enableShardingActions.addAction(ActionType::reshardCollection);
+ ac1.addPrivilege(Privilege(ResourcePattern::forAnyNormalResource(), enableShardingActions));
+
+ AuthorizationContract ac2(
+ std::initializer_list<AccessCheckEnum>{AccessCheckEnum::kIsAuthenticated,
+ AccessCheckEnum::kIsCoAuthorized},
+ std::initializer_list<Privilege>{Privilege(ResourcePattern::forAnyNormalResource(),
+ {ActionType::enableSharding,
+ ActionType::refineCollectionShardKey,
+ ActionType::reshardCollection})});
+
+ ASSERT_TRUE(ac1.contains(ac2));
+ ASSERT_TRUE(ac2.contains(ac1));
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 517117dd298..c983ba68313 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -606,7 +606,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateEmptyPipelineWithoutFindAction)
}
TEST_F(AuthorizationSessionTest, CanAggregateEmptyPipelineWithFindAction) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
testFooNss,
@@ -634,7 +634,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateWithoutFindActionIfFirstStageNot
}
TEST_F(AuthorizationSessionTest, CannotAggregateWithFindActionIfPipelineContainsIndexOrCollStats) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$limit" << 1) << BSON("$collStats" << BSONObj())
<< BSON("$indexStats" << BSONObj()));
@@ -648,7 +648,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateWithFindActionIfPipelineContains
}
TEST_F(AuthorizationSessionTest, CannotAggregateCollStatsWithoutCollStatsAction) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$collStats" << BSONObj()));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -661,7 +661,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCollStatsWithoutCollStatsAction)
}
TEST_F(AuthorizationSessionTest, CanAggregateCollStatsWithCollStatsAction) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::collStats}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::collStats));
BSONArray pipeline = BSON_ARRAY(BSON("$collStats" << BSONObj()));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -674,7 +674,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateCollStatsWithCollStatsAction) {
}
TEST_F(AuthorizationSessionTest, CannotAggregateIndexStatsWithoutIndexStatsAction) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$indexStats" << BSONObj()));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -687,7 +687,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateIndexStatsWithoutIndexStatsActio
}
TEST_F(AuthorizationSessionTest, CanAggregateIndexStatsWithIndexStatsAction) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::indexStats}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::indexStats));
BSONArray pipeline = BSON_ARRAY(BSON("$indexStats" << BSONObj()));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -700,7 +700,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateIndexStatsWithIndexStatsAction) {
}
TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersFalseWithoutInprogActionOnMongoD) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << false)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -713,7 +713,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersFalseWithoutInprog
}
TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersFalseWithoutInprogActionOnMongoS) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << false)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -747,7 +747,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersFalseIfNotAuthe
}
TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInprogActionOnMongoD) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << true)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -760,7 +760,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInpr
}
TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInprogActionOnMongoS) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << true)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -774,7 +774,7 @@ TEST_F(AuthorizationSessionTest, CannotAggregateCurrentOpAllUsersTrueWithoutInpr
TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActionOnMongoD) {
authzSession->assumePrivilegesForDB(
- Privilege(ResourcePattern::forClusterResource(), {ActionType::inprog}));
+ Privilege(ResourcePattern::forClusterResource(), ActionType::inprog));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << true)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -788,7 +788,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActi
TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActionOnMongoS) {
authzSession->assumePrivilegesForDB(
- Privilege(ResourcePattern::forClusterResource(), {ActionType::inprog}));
+ Privilege(ResourcePattern::forClusterResource(), ActionType::inprog));
BSONArray pipeline = BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << true)));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -801,7 +801,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateCurrentOpAllUsersTrueWithInprogActi
}
TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMongoD) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline =
BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << false << "allUsers" << true)));
@@ -815,7 +815,7 @@ TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMon
}
TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMongoS) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline =
BSON_ARRAY(BSON("$currentOp" << BSON("allUsers" << false << "allUsers" << true)));
@@ -829,7 +829,7 @@ TEST_F(AuthorizationSessionTest, CannotSpoofAllUsersTrueWithoutInprogActionOnMon
}
TEST_F(AuthorizationSessionTest, AddPrivilegesForStageFailsIfOutNamespaceIsNotValid) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$out"
<< ""));
@@ -845,7 +845,7 @@ TEST_F(AuthorizationSessionTest, AddPrivilegesForStageFailsIfOutNamespaceIsNotVa
TEST_F(AuthorizationSessionTest, CannotAggregateOutWithoutInsertAndRemoveOnTargetNamespace) {
// We only have find on the aggregation namespace.
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$out" << testBarNss.coll()));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -857,19 +857,19 @@ TEST_F(AuthorizationSessionTest, CannotAggregateOutWithoutInsertAndRemoveOnTarge
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
// We have insert but not remove on the $out namespace.
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::insert})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::insert)});
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
// We have remove but not insert on the $out namespace.
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::remove})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::remove)});
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
}
TEST_F(AuthorizationSessionTest, CanAggregateOutWithInsertAndRemoveOnTargetNamespace) {
authzSession->assumePrivilegesForDB(
- {Privilege(testFooCollResource, {ActionType::find}),
+ {Privilege(testFooCollResource, ActionType::find),
Privilege(testBarCollResource, {ActionType::insert, ActionType::remove})});
BSONArray pipeline = BSON_ARRAY(BSON("$out" << testBarNss.coll()));
@@ -896,7 +896,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateOutWithInsertAndRemoveOnTargetNames
TEST_F(AuthorizationSessionTest,
CannotAggregateOutBypassingValidationWithoutBypassDocumentValidationOnTargetNamespace) {
authzSession->assumePrivilegesForDB(
- {Privilege(testFooCollResource, {ActionType::find}),
+ {Privilege(testFooCollResource, ActionType::find),
Privilege(testBarCollResource, {ActionType::insert, ActionType::remove})});
BSONArray pipeline = BSON_ARRAY(BSON("$out" << testBarNss.coll()));
@@ -912,7 +912,7 @@ TEST_F(AuthorizationSessionTest,
TEST_F(AuthorizationSessionTest,
CanAggregateOutBypassingValidationWithBypassDocumentValidationOnTargetNamespace) {
authzSession->assumePrivilegesForDB(
- {Privilege(testFooCollResource, {ActionType::find}),
+ {Privilege(testFooCollResource, ActionType::find),
Privilege(
testBarCollResource,
{ActionType::insert, ActionType::remove, ActionType::bypassDocumentValidation})});
@@ -928,7 +928,7 @@ TEST_F(AuthorizationSessionTest,
}
TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnJoinedNamespace) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$lookup" << BSON("from" << testBarNss.coll())));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -941,8 +941,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnJoinedNamespa
}
TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnJoinedNamespace) {
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find)});
BSONArray pipeline = BSON_ARRAY(BSON("$lookup" << BSON("from" << testBarNss.coll())));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -956,8 +956,8 @@ TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnJoinedNamespace) {
TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnNestedJoinedNamespace) {
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find)});
BSONArray nestedPipeline = BSON_ARRAY(BSON("$lookup" << BSON("from" << testQuxNss.coll())));
BSONArray pipeline = BSON_ARRAY(
@@ -972,9 +972,9 @@ TEST_F(AuthorizationSessionTest, CannotAggregateLookupWithoutFindOnNestedJoinedN
}
TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnNestedJoinedNamespace) {
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find}),
- Privilege(testQuxCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find),
+ Privilege(testQuxCollResource, ActionType::find)});
BSONArray nestedPipeline = BSON_ARRAY(BSON("$lookup" << BSON("from" << testQuxNss.coll())));
BSONArray pipeline = BSON_ARRAY(
@@ -989,7 +989,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateLookupWithFindOnNestedJoinedNamespa
}
TEST_F(AuthorizationSessionTest, CheckAuthForAggregateWithDeeplyNestedLookup) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
// Recursively adds nested $lookup stages to 'pipelineBob', building a pipeline with
// 'levelsToGo' deep $lookup stages.
@@ -1035,7 +1035,7 @@ TEST_F(AuthorizationSessionTest, CheckAuthForAggregateWithDeeplyNestedLookup) {
TEST_F(AuthorizationSessionTest, CannotAggregateGraphLookupWithoutFindOnJoinedNamespace) {
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline = BSON_ARRAY(BSON("$graphLookup" << BSON("from" << testBarNss.coll())));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -1048,8 +1048,8 @@ TEST_F(AuthorizationSessionTest, CannotAggregateGraphLookupWithoutFindOnJoinedNa
}
TEST_F(AuthorizationSessionTest, CanAggregateGraphLookupWithFindOnJoinedNamespace) {
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find)});
BSONArray pipeline = BSON_ARRAY(BSON("$graphLookup" << BSON("from" << testBarNss.coll())));
auto aggReq = uassertStatusOK(aggregation_request_helper::parseFromBSONForTests(
@@ -1064,7 +1064,7 @@ TEST_F(AuthorizationSessionTest, CanAggregateGraphLookupWithFindOnJoinedNamespac
TEST_F(AuthorizationSessionTest,
CannotAggregateFacetWithLookupAndGraphLookupWithoutFindOnJoinedNamespaces) {
// We only have find on the aggregation namespace.
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
BSONArray pipeline =
BSON_ARRAY(fromjson("{$facet: {lookup: [{$lookup: {from: 'bar'}}], graphLookup: "
@@ -1078,21 +1078,21 @@ TEST_F(AuthorizationSessionTest,
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
// We have find on the $lookup namespace but not on the $graphLookup namespace.
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find)});
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
// We have find on the $graphLookup namespace but not on the $lookup namespace.
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testQuxCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testQuxCollResource, ActionType::find)});
ASSERT_FALSE(authzSession->isAuthorizedForPrivileges(privileges));
}
TEST_F(AuthorizationSessionTest,
CanAggregateFacetWithLookupAndGraphLookupWithFindOnJoinedNamespaces) {
- authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, {ActionType::find}),
- Privilege(testBarCollResource, {ActionType::find}),
- Privilege(testQuxCollResource, {ActionType::find})});
+ authzSession->assumePrivilegesForDB({Privilege(testFooCollResource, ActionType::find),
+ Privilege(testBarCollResource, ActionType::find),
+ Privilege(testQuxCollResource, ActionType::find)});
BSONArray pipeline =
BSON_ARRAY(fromjson("{$facet: {lookup: [{$lookup: {from: 'bar'}}], graphLookup: "
@@ -1253,7 +1253,7 @@ TEST_F(AuthorizationSessionTest, CannotListCollectionsWithoutListCollectionsPriv
TEST_F(AuthorizationSessionTest, CanListCollectionsWithListCollectionsPrivilege) {
BSONObj cmd = BSON("listCollections" << 1);
// The listCollections privilege authorizes the list collections command.
- authzSession->assumePrivilegesForDB(Privilege(testDBResource, {ActionType::listCollections}));
+ authzSession->assumePrivilegesForDB(Privilege(testDBResource, ActionType::listCollections));
ASSERT_OK(authzSession->checkAuthorizedToListCollections(testFooNss.db(), cmd).getStatus());
ASSERT_OK(authzSession->checkAuthorizedToListCollections(testBarNss.db(), cmd).getStatus());
@@ -1264,7 +1264,7 @@ TEST_F(AuthorizationSessionTest, CanListOwnCollectionsWithPrivilege) {
BSONObj cmd =
BSON("listCollections" << 1 << "nameOnly" << true << "authorizedCollections" << true);
// The listCollections privilege authorizes the list collections command.
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
ASSERT_OK(authzSession->checkAuthorizedToListCollections(testFooNss.db(), cmd).getStatus());
ASSERT_OK(authzSession->checkAuthorizedToListCollections(testBarNss.db(), cmd).getStatus());
@@ -1278,7 +1278,7 @@ TEST_F(AuthorizationSessionTest, CanCheckIfHasAnyPrivilegeOnResource) {
ASSERT_FALSE(authzSession->isAuthorizedForAnyActionOnResource(testFooCollResource));
// If we have a collection privilege, we have actions on that collection
- authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, {ActionType::find}));
+ authzSession->assumePrivilegesForDB(Privilege(testFooCollResource, ActionType::find));
ASSERT_TRUE(authzSession->isAuthorizedForAnyActionOnResource(testFooCollResource));
ASSERT_FALSE(authzSession->isAuthorizedForAnyActionOnResource(
ResourcePattern::forDatabaseName(testFooNss.db())));
@@ -1290,7 +1290,7 @@ TEST_F(AuthorizationSessionTest, CanCheckIfHasAnyPrivilegeOnResource) {
// If we have a database privilege, we have actions on that database and all collections it
// contains
authzSession->assumePrivilegesForDB(
- Privilege(ResourcePattern::forDatabaseName(testFooNss.db()), {ActionType::find}));
+ Privilege(ResourcePattern::forDatabaseName(testFooNss.db()), ActionType::find));
ASSERT_TRUE(authzSession->isAuthorizedForAnyActionOnResource(testFooCollResource));
ASSERT_TRUE(authzSession->isAuthorizedForAnyActionOnResource(
ResourcePattern::forDatabaseName(testFooNss.db())));
@@ -1302,7 +1302,7 @@ TEST_F(AuthorizationSessionTest, CanCheckIfHasAnyPrivilegeOnResource) {
// If we have a privilege on anyNormalResource, we have actions on all databases and all
// collections they contain
authzSession->assumePrivilegesForDB(
- Privilege(ResourcePattern::forAnyNormalResource(), {ActionType::find}));
+ Privilege(ResourcePattern::forAnyNormalResource(), ActionType::find));
ASSERT_TRUE(authzSession->isAuthorizedForAnyActionOnResource(testFooCollResource));
ASSERT_TRUE(authzSession->isAuthorizedForAnyActionOnResource(
ResourcePattern::forDatabaseName(testFooNss.db())));
@@ -1331,7 +1331,7 @@ TEST_F(AuthorizationSessionTest, CanUseUUIDNamespacesWithPrivilege) {
// The useUUID privilege allows UUIDs to be parsed
authzSession->assumePrivilegesForDB(
- Privilege(ResourcePattern::forClusterResource(), {ActionType::useUUID}));
+ Privilege(ResourcePattern::forClusterResource(), ActionType::useUUID));
ASSERT_TRUE(authzSession->isAuthorizedToParseNamespaceElement(stringObj.firstElement()));
ASSERT_TRUE(authzSession->isAuthorizedToParseNamespaceElement(uuidObj.firstElement()));
diff --git a/src/mongo/db/auth/privilege.cpp b/src/mongo/db/auth/privilege.cpp
index 032124b1a52..dc3cd1d75a1 100644
--- a/src/mongo/db/auth/privilege.cpp
+++ b/src/mongo/db/auth/privilege.cpp
@@ -54,7 +54,7 @@ void Privilege::addPrivilegesToPrivilegeVector(PrivilegeVector* privileges,
}
}
-Privilege::Privilege(const ResourcePattern& resource, const ActionType& action)
+Privilege::Privilege(const ResourcePattern& resource, const ActionType action)
: _resource(resource) {
_actions.addAction(action);
}
@@ -69,7 +69,7 @@ void Privilege::removeActions(const ActionSet& actionsToRemove) {
_actions.removeAllActionsFromSet(actionsToRemove);
}
-bool Privilege::includesAction(const ActionType& action) const {
+bool Privilege::includesAction(const ActionType action) const {
return _actions.contains(action);
}
diff --git a/src/mongo/db/auth/privilege.h b/src/mongo/db/auth/privilege.h
index 643ad18e984..48c0c238091 100644
--- a/src/mongo/db/auth/privilege.h
+++ b/src/mongo/db/auth/privilege.h
@@ -75,7 +75,7 @@ public:
Privilege(Privilege&&) = default;
Privilege& operator=(Privilege&&) = default;
- Privilege(const ResourcePattern& resource, const ActionType& action);
+ Privilege(const ResourcePattern& resource, const ActionType action);
Privilege(const ResourcePattern& resource, const ActionSet& actions);
const ResourcePattern& getResourcePattern() const {
@@ -90,7 +90,7 @@ public:
void removeActions(const ActionSet& actionsToRemove);
// Checks if the given action is present in the Privilege.
- bool includesAction(const ActionType& action) const;
+ bool includesAction(const ActionType action) const;
// Checks if the given actions are present in the Privilege.
bool includesActions(const ActionSet& actions) const;
diff --git a/src/mongo/db/auth/resource_pattern.h b/src/mongo/db/auth/resource_pattern.h
index df85f83a73a..6f51a768120 100644
--- a/src/mongo/db/auth/resource_pattern.h
+++ b/src/mongo/db/auth/resource_pattern.h
@@ -49,6 +49,8 @@ namespace mongo {
* authorization_session.cpp for details.
*/
class ResourcePattern {
+ friend class AuthorizationContract;
+
public:
/**
* Returns a pattern that matches absolutely any resource.
@@ -188,6 +190,13 @@ public:
}
private:
+ // AuthorizationContract works directly with MatchTypeEnum. Users should not be concerned with
+ // how a ResourcePattern was constructed.
+ MatchTypeEnum matchType() const {
+ return _matchType;
+ }
+
+private:
explicit ResourcePattern(MatchTypeEnum type) : _matchType(type) {}
ResourcePattern(MatchTypeEnum type, const NamespaceString& ns) : _matchType(type), _ns(ns) {}