This is an automated email from the ASF dual-hosted git repository. mzhu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 2ae1296c668686d234be92b00bd7abbc0a6194b0 Author: Meng Zhu <[email protected]> AuthorDate: Thu Apr 25 16:03:36 2019 -0700 Added `UPDATE_QUOTA_WITH_CONFIG` authorization in the local authorizor. Also added a test. Review: https://reviews.apache.org/r/70550 --- include/mesos/authorizer/acls.proto | 2 + src/authorizer/local/authorizer.cpp | 15 ++- src/tests/authorization_tests.cpp | 196 ++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 1 deletion(-) diff --git a/include/mesos/authorizer/acls.proto b/include/mesos/authorizer/acls.proto index 85a3979..78acfe6 100644 --- a/include/mesos/authorizer/acls.proto +++ b/include/mesos/authorizer/acls.proto @@ -133,6 +133,8 @@ message ACL { } // Which principals are authorized to update quotas for the given roles. + // This ACL is currently used for two authorizatble actions: + // `UPDATE_QUOTA` and `UPDATE_QUOTA_WITH_CONFIG`. message UpdateQuota { // Subjects: Operator username. required Entity principals = 1; diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp index ec86f05..b89010d 100644 --- a/src/authorizer/local/authorizer.cpp +++ b/src/authorizer/local/authorizer.cpp @@ -424,6 +424,7 @@ public: case authorization::GET_QUOTA: case authorization::RESERVE_RESOURCES: case authorization::UPDATE_QUOTA: + case authorization::UPDATE_QUOTA_WITH_CONFIG: case authorization::UPDATE_WEIGHT: case authorization::VIEW_ROLE: case authorization::REGISTER_FRAMEWORK: @@ -669,6 +670,15 @@ public: break; } + case authorization::UPDATE_QUOTA_WITH_CONFIG: { + // Check object has the required types set. + CHECK_NOTNULL(object->value); + + entityObject.add_values(*(object->value)); + entityObject.set_type(mesos::ACL::Entity::SOME); + + break; + } case authorization::REGISTER_FRAMEWORK: { vector<ACL::Entity> objects; if (object->framework_info) { @@ -922,7 +932,8 @@ public: createHierarchicalRoleACLs(acls.register_frameworks()); break; } - case authorization::UPDATE_QUOTA: { + case authorization::UPDATE_QUOTA: + case authorization::UPDATE_QUOTA_WITH_CONFIG: { hierarchicalRoleACLs = createHierarchicalRoleACLs(acls.update_quotas()); break; @@ -1171,6 +1182,7 @@ public: case authorization::GET_QUOTA: case authorization::REGISTER_FRAMEWORK: case authorization::UPDATE_QUOTA: + case authorization::UPDATE_QUOTA_WITH_CONFIG: case authorization::CREATE_BLOCK_DISK: case authorization::DESTROY_BLOCK_DISK: case authorization::CREATE_MOUNT_DISK: @@ -1608,6 +1620,7 @@ private: case authorization::VIEW_ROLE: case authorization::GET_QUOTA: case authorization::UPDATE_QUOTA: + case authorization::UPDATE_QUOTA_WITH_CONFIG: case authorization::LAUNCH_NESTED_CONTAINER_SESSION: case authorization::LAUNCH_NESTED_CONTAINER: case authorization::CREATE_BLOCK_DISK: diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp index cad76f6..7bb0bd8 100644 --- a/src/tests/authorization_tests.cpp +++ b/src/tests/authorization_tests.cpp @@ -2466,6 +2466,202 @@ TYPED_TEST(AuthorizationTest, UpdateQuota) } +// This tests the authorization of requests to update quota configs. +TYPED_TEST(AuthorizationTest, UpdateQuotaConfig) +{ + ACLs acls; + + { + // "foo" principal can update quota configs for all roles. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_roles()->set_type(mesos::ACL::Entity::ANY); + } + + { + // "bar" principal can update quota configs for "dev" role. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->add_values("bar"); + acl->mutable_roles()->add_values("dev"); + } + + { + // Anyone can update quota configs for "test" role. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); + acl->mutable_roles()->add_values("test"); + } + + { + // Principal "elizabeth-ii" can update quota configs for the "king" role + // and its nested ones. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->add_values("elizabeth-ii"); + acl->mutable_roles()->add_values("king/%"); + acl->mutable_roles()->add_values("king"); + } + + { + // Principal "charles" can update quota configs for any role below the + // "king/" role. Not in "king" itself. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->add_values("charles"); + acl->mutable_roles()->add_values("king/%"); + } + + { + // Principal "j-welby" can update quota configs only for the "king" role + // but not in any nested one. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->add_values("j-welby"); + acl->mutable_roles()->add_values("king"); + } + + { + // No other principal can update quota configs. + mesos::ACL::UpdateQuota* acl = acls.add_update_quotas(); + acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); + acl->mutable_roles()->set_type(mesos::ACL::Entity::NONE); + } + + // Create an `Authorizer` with the ACLs. + Try<Authorizer*> create = TypeParam::create(parameterize(acls)); + ASSERT_SOME(create); + Owned<Authorizer> authorizer(create.get()); + + // Principal "foo" can update quota configs for all roles, so this will pass. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("foo"); + request.mutable_object()->set_value("prod"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + // Principal "bar" can update quota configs for role "dev", so this will pass. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("bar"); + request.mutable_object()->set_value("dev"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + // Principal "bar" can only update quota configs for role "dev", + // so this will fail. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("bar"); + request.mutable_object()->set_value("prod"); + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + // Anyone can update quota configs for role "test", so this will pass. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_object()->set_value("test"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + // Principal "jeff" is not mentioned in the ACLs of the `Authorizer`, so it + // will be caught by the final ACL, which provides a default case that denies + // access for all other principals. This case will fail. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("jeff"); + request.mutable_object()->set_value("prod"); + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + // `elizabeth-ii` has full permissions for the `king` role as well as all + // its nested roles. She should be able to update quota configs in the next + // three blocks. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("elizabeth-ii"); + request.mutable_object()->set_value("king"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("elizabeth-ii"); + request.mutable_object()->set_value("king/prince"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("elizabeth-ii"); + request.mutable_object() + ->set_value("king/prince/duke"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + // `charles` doesn't have permissions for the `king` role, so the first + // test should fail. However he has permissions for `king`'s nested roles + // so the next two tests should succeed. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("charles"); + request.mutable_object()->set_value("king"); + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("charles"); + request.mutable_object()->set_value("king/prince"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("charles"); + request.mutable_object() + ->set_value("king/prince/duke"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + // `j-welby` only has permissions for the role `king` itself, but not + // for its nested roles, therefore only the first of the following three + // tests should succeed. + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("j-welby"); + request.mutable_object()->set_value("king"); + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("j-welby"); + request.mutable_object()->set_value("king/prince"); + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + { + authorization::Request request; + request.set_action(authorization::UPDATE_QUOTA_WITH_CONFIG); + request.mutable_subject()->set_value("j-welby"); + request.mutable_object() + ->set_value("king/prince/duke"); + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } +} + + // This tests the authorization of requests to ViewFramework. TYPED_TEST(AuthorizationTest, ViewFramework) {
