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)
 {

Reply via email to