You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by me...@apache.org on 2017/04/27 08:17:44 UTC
[1/2] mesos git commit: Added support for authorization of
Hierachical roles.
Repository: mesos
Updated Branches:
refs/heads/master 2cde52884 -> d55148afb
Added support for authorization of Hierachical roles.
Adds mechanisms to support authorization of hierarchical roles,
that is, it allows operators to write ACLs of the form role/%
which will enforce the rule for any nested role, e.g. role/a,
role/b and such.
Review: https://reviews.apache.org/r/57473/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/d46d3307
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/d46d3307
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/d46d3307
Branch: refs/heads/master
Commit: d46d33079805379515de0c300d7e6f4286adeb77
Parents: 2cde528
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Thu Apr 27 00:02:06 2017 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Thu Apr 27 00:03:26 2017 -0700
----------------------------------------------------------------------
src/authorizer/local/authorizer.cpp | 537 ++++++++++++++++++++++---------
1 file changed, 384 insertions(+), 153 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/d46d3307/src/authorizer/local/authorizer.cpp
----------------------------------------------------------------------
diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp
index 3eb59d3..9082fb1 100644
--- a/src/authorizer/local/authorizer.cpp
+++ b/src/authorizer/local/authorizer.cpp
@@ -199,8 +199,6 @@ public:
aclObject.set_type(mesos::ACL::Entity::ANY);
} else {
switch (action_) {
- // All actions using `object.value` for authorization.
- case authorization::VIEW_ROLE:
case authorization::GET_ENDPOINT_WITH_PATH:
// Check object has the required types set.
CHECK_NOTNULL(object->value);
@@ -209,25 +207,6 @@ public:
aclObject.set_type(mesos::ACL::Entity::SOME);
break;
- case authorization::REGISTER_FRAMEWORK:
- aclObject.set_type(mesos::ACL::Entity::SOME);
- if (object->framework_info) {
- foreach (
- const string& role,
- protobuf::framework::getRoles(*object->framework_info)) {
- aclObject.add_values(role);
- }
- } else if (object->value) {
- // We also update the deprecated `value` field to support custom
- // authorizers not yet modified to examine `framework_info`.
- //
- // TODO(bbannier): Clean up use of `value` here, see MESOS-7091.
- aclObject.add_values(*(object->value));
- } else {
- aclObject.set_type(mesos::ACL::Entity::ANY);
- }
-
- break;
case authorization::TEARDOWN_FRAMEWORK:
aclObject.set_type(mesos::ACL::Entity::SOME);
if (object->framework_info) {
@@ -239,18 +218,6 @@ public:
}
break;
- case authorization::CREATE_VOLUME:
- case authorization::RESERVE_RESOURCES:
- aclObject.set_type(mesos::ACL::Entity::SOME);
- if (object->resource) {
- aclObject.add_values(object->resource->role());
- } else if (object->value) {
- aclObject.add_values(*(object->value));
- } else {
- aclObject.set_type(mesos::ACL::Entity::ANY);
- }
-
- break;
case authorization::DESTROY_VOLUME:
aclObject.set_type(mesos::ACL::Entity::SOME);
if (object->resource) {
@@ -274,28 +241,6 @@ public:
}
break;
- case authorization::GET_QUOTA:
- aclObject.set_type(mesos::ACL::Entity::SOME);
- if (object->quota_info) {
- aclObject.add_values(object->quota_info->role());
- } else if (object->value) {
- aclObject.add_values(*(object->value));
- } else {
- aclObject.set_type(mesos::ACL::Entity::ANY);
- }
-
- break;
- case authorization::UPDATE_WEIGHT:
- aclObject.set_type(mesos::ACL::Entity::SOME);
- if (object->weight_info) {
- aclObject.add_values(object->weight_info->role());
- } else if (object->value) {
- aclObject.add_values(*(object->value));
- } else {
- aclObject.set_type(mesos::ACL::Entity::ANY);
- }
-
- break;
case authorization::RUN_TASK:
aclObject.set_type(mesos::ACL::Entity::SOME);
if (object->task_info && object->task_info->has_command() &&
@@ -354,14 +299,6 @@ public:
}
break;
- case authorization::UPDATE_QUOTA:
- // Check object has the required types set.
- CHECK_NOTNULL(object->quota_info);
-
- aclObject.add_values(object->quota_info->role());
- aclObject.set_type(mesos::ACL::Entity::SOME);
-
- break;
case authorization::VIEW_FRAMEWORK:
// Check object has the required types set.
CHECK_NOTNULL(object->framework_info);
@@ -455,11 +392,19 @@ public:
aclObject.set_type(mesos::ACL::Entity::ANY);
break;
+ case authorization::CREATE_VOLUME:
+ case authorization::GET_QUOTA:
+ case authorization::RESERVE_RESOURCES:
+ case authorization::UPDATE_QUOTA:
+ case authorization::UPDATE_WEIGHT:
+ case authorization::VIEW_ROLE:
+ case authorization::REGISTER_FRAMEWORK:
+ return Error("Authorization for action " + stringify(action_) +
+ " requires a specialized approver object.");
case authorization::UNKNOWN:
LOG(WARNING) << "Authorization for action '" << action_
<< "' is not defined and therefore not authorized";
return false;
- break;
}
}
@@ -575,6 +520,207 @@ public:
};
+class LocalHierarchicalRoleApprover : public ObjectApprover
+{
+public:
+ LocalHierarchicalRoleApprover(
+ const vector<GenericACL>& acls,
+ const Option<authorization::Subject>& subject,
+ const authorization::Action& action,
+ bool permissive)
+ : acls_(acls), subject_(subject), action_(action), permissive_(permissive)
+ {
+ if (subject_.isSome()) {
+ entitySubject_.set_type(ACL::Entity::SOME);
+ entitySubject_.add_values(subject_->value());
+ } else {
+ entitySubject_.set_type(ACL::Entity::ANY);
+ }
+ }
+
+ virtual Try<bool> approved(const Option<ObjectApprover::Object>& object) const
+ noexcept override
+ {
+ ACL::Entity entityObject;
+
+ if (object.isNone()) {
+ entityObject.set_type(ACL::Entity::ANY);
+ } else {
+ switch (action_) {
+ case authorization::CREATE_VOLUME:
+ case authorization::RESERVE_RESOURCES: {
+ entityObject.set_type(ACL::Entity::SOME);
+ if (object->resource) {
+ entityObject.add_values(object->resource->role());
+ } else if (object->value) {
+ entityObject.add_values(*(object->value));
+ } else {
+ entityObject.set_type(ACL::Entity::ANY);
+ }
+ break;
+ }
+ case authorization::UPDATE_WEIGHT: {
+ entityObject.set_type(mesos::ACL::Entity::SOME);
+ if (object->weight_info) {
+ entityObject.add_values(object->weight_info->role());
+ } else if (object->value) {
+ entityObject.add_values(*(object->value));
+ } else {
+ entityObject.set_type(mesos::ACL::Entity::ANY);
+ }
+
+ break;
+ }
+ case authorization::VIEW_ROLE: {
+ // 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::GET_QUOTA: {
+ entityObject.set_type(mesos::ACL::Entity::SOME);
+ if (object->quota_info) {
+ entityObject.add_values(object->quota_info->role());
+ } else if (object->value) {
+ entityObject.add_values(*(object->value));
+ } else {
+ entityObject.set_type(mesos::ACL::Entity::ANY);
+ }
+
+ break;
+ }
+ case authorization::UPDATE_QUOTA: {
+ // Check object has the required types set.
+ CHECK_NOTNULL(object->quota_info);
+
+ entityObject.add_values(object->quota_info->role());
+ entityObject.set_type(mesos::ACL::Entity::SOME);
+
+ break;
+ }
+ case authorization::REGISTER_FRAMEWORK: {
+ vector<ACL::Entity> objects;
+ if (object->framework_info) {
+ foreach (
+ const string& role,
+ protobuf::framework::getRoles(*(object->framework_info))) {
+ objects.emplace_back();
+ objects.back().set_type(mesos::ACL::Entity::SOME);
+ objects.back().add_values(role);
+ }
+ } else if (object->value) {
+ // We also update the deprecated `value` field to support custom
+ // authorizers not yet modified to examine `framework_info`.
+ //
+ // TODO(bbannier): Clean up use of `value` here, see MESOS-7091.
+ objects.emplace_back();
+ objects.back().set_type(mesos::ACL::Entity::SOME);
+ objects.back().add_values(*(object->value));
+ } else {
+ objects.emplace_back();
+ objects.back().set_type(mesos::ACL::Entity::ANY);
+ }
+
+ // The framework needs to be allowed to register under
+ // all the roles it requests.
+ foreach (const ACL::Entity& entity, objects) {
+ if (!approved(acls_, entitySubject_, entity)) {
+ return false;
+ }
+ }
+
+ return objects.empty() ? permissive_ : true;
+ }
+ case authorization::ACCESS_MESOS_LOG:
+ case authorization::ACCESS_SANDBOX:
+ case authorization::ATTACH_CONTAINER_INPUT:
+ case authorization::ATTACH_CONTAINER_OUTPUT:
+ case authorization::DESTROY_VOLUME:
+ case authorization::GET_ENDPOINT_WITH_PATH:
+ case authorization::KILL_NESTED_CONTAINER:
+ case authorization::LAUNCH_NESTED_CONTAINER:
+ case authorization::LAUNCH_NESTED_CONTAINER_SESSION:
+ case authorization::REMOVE_NESTED_CONTAINER:
+ case authorization::RUN_TASK:
+ case authorization::SET_LOG_LEVEL:
+ case authorization::TEARDOWN_FRAMEWORK:
+ case authorization::UNRESERVE_RESOURCES:
+ case authorization::VIEW_CONTAINER:
+ case authorization::VIEW_EXECUTOR:
+ case authorization::VIEW_FLAGS:
+ case authorization::VIEW_FRAMEWORK:
+ case authorization::VIEW_TASK:
+ case authorization::WAIT_NESTED_CONTAINER:
+ case authorization::UNKNOWN:
+ UNREACHABLE();
+ }
+ }
+
+ CHECK(
+ entityObject.type() == ACL::Entity::ANY ||
+ entityObject.values_size() == 1);
+
+ return approved(acls_, entitySubject_, entityObject);
+ }
+
+private:
+ bool approved(
+ const vector<GenericACL>& acls,
+ const ACL::Entity& subject,
+ const ACL::Entity& object) const
+ {
+ // This entity is used for recursive hierarchies where we already
+ // validated that the object role is a nested hierarchy of the
+ // acl role.
+ ACL::Entity aclAny;
+ aclAny.set_type(ACL::Entity::ANY);
+
+ foreach (const GenericACL& acl, acls) {
+ if (!isRecursiveACL(acl)) {
+ // If `acl` is not recursive, treat it as a normal acl.
+ if (matches(subject, acl.subjects) && matches(object, acl.objects)) {
+ return allows(subject, acl.subjects) && allows(object, acl.objects);
+ }
+ } else if (object.type() == ACL::Entity::SOME &&
+ isNestedHierarchy(acl.objects.values(0), object.values(0))) {
+ // Partial validation was done when verifying that the object is
+ // a nested hierarchy.
+ if (matches(subject, acl.subjects) && matches(object, aclAny)) {
+ return allows(subject, acl.subjects) && allows(object, aclAny);
+ }
+ }
+ }
+
+ return permissive_;
+ }
+
+ static bool isRecursiveACL(const GenericACL& acl)
+ {
+ return acl.objects.values_size() == 1 &&
+ strings::endsWith(acl.objects.values(0), "/%");
+ }
+
+ // Returns true if child is a nested hierarchy of parent, i.e. child has more
+ // levels of nesting and all the levels of parent are a prefix of the levels
+ // of child.
+ static bool isNestedHierarchy(const string& parent, const string& child)
+ {
+ // Requires that parent ends with `/%`.
+ CHECK(strings::endsWith(parent, "/%"));
+ return strings::startsWith(child, parent.substr(0, parent.size() - 1));
+ }
+
+ vector<GenericACL> acls_;
+ Option<authorization::Subject> subject_;
+ authorization::Action action_;
+ bool permissive_;
+ ACL::Entity entitySubject_;
+};
+
+
class LocalAuthorizerProcess : public ProtobufProcess<LocalAuthorizerProcess>
{
public:
@@ -630,9 +776,127 @@ public:
});
}
+ template <typename SomeACL>
+ static vector<GenericACL> createHierarchicalRoleACLs(
+ SomeACL&& someACL)
+ {
+ vector<GenericACL> acls;
+
+ // This may split an ACL into several. This does not change semantics
+ // since the split rules appear consecutively and if an object
+ // matches any of the split ACLs in any order, it will yield the same
+ // results.
+ foreach (auto&& acl, someACL) {
+ switch (acl.roles().type()) {
+ case ACL::Entity::SOME: {
+ ACL::Entity roles;
+ foreach (const string& value, acl.roles().values()) {
+ if (strings::endsWith(value, "/%")) {
+ // Recursive ACLs only have one value in their object list.
+ GenericACL acl_;
+ acl_.subjects = acl.principals();
+ acl_.objects.add_values(value);
+ acls.push_back(acl_);
+ } else {
+ roles.add_values(value);
+ }
+ }
+
+ if (!roles.values().empty()) {
+ GenericACL acl_;
+ acl_.subjects = acl.principals();
+ acl_.objects = roles;
+ acls.push_back(acl_);
+ }
+ break;
+ }
+ case ACL::Entity::ANY:
+ case ACL::Entity::NONE: {
+ GenericACL acl_;
+ acl_.subjects = acl.principals();
+ acl_.objects = acl.roles();
+ acls.push_back(acl_);
+ break;
+ }
+ }
+ }
+
+ return acls;
+ }
+
+ Future<Owned<ObjectApprover>> getHierarchicalRoleApprover(
+ const Option<authorization::Subject>& subject,
+ const authorization::Action& action) const
+ {
+ vector<GenericACL> hierarchicalRoleACLs;
+ switch (action) {
+ case authorization::CREATE_VOLUME: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.create_volumes());
+ break;
+ }
+ case authorization::RESERVE_RESOURCES: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.reserve_resources());
+ break;
+ }
+ case authorization::UPDATE_WEIGHT: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.update_weights());
+ break;
+ }
+ case authorization::VIEW_ROLE: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.view_roles());
+ break;
+ }
+ case authorization::GET_QUOTA: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.get_quotas());
+ break;
+ }
+ case authorization::REGISTER_FRAMEWORK: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.register_frameworks());
+ break;
+ }
+ case authorization::UPDATE_QUOTA: {
+ hierarchicalRoleACLs =
+ createHierarchicalRoleACLs(acls.update_quotas());
+ break;
+ }
+ case authorization::ACCESS_MESOS_LOG:
+ case authorization::ACCESS_SANDBOX:
+ case authorization::ATTACH_CONTAINER_INPUT:
+ case authorization::ATTACH_CONTAINER_OUTPUT:
+ case authorization::DESTROY_VOLUME:
+ case authorization::GET_ENDPOINT_WITH_PATH:
+ case authorization::KILL_NESTED_CONTAINER:
+ case authorization::LAUNCH_NESTED_CONTAINER:
+ case authorization::LAUNCH_NESTED_CONTAINER_SESSION:
+ case authorization::RUN_TASK:
+ case authorization::SET_LOG_LEVEL:
+ case authorization::TEARDOWN_FRAMEWORK:
+ case authorization::UNKNOWN:
+ case authorization::UNRESERVE_RESOURCES:
+ case authorization::VIEW_CONTAINER:
+ case authorization::VIEW_EXECUTOR:
+ case authorization::VIEW_FLAGS:
+ case authorization::VIEW_FRAMEWORK:
+ case authorization::VIEW_TASK:
+ case authorization::WAIT_NESTED_CONTAINER:
+ case authorization::REMOVE_NESTED_CONTAINER:
+ UNREACHABLE();
+ }
+
+ return Owned<ObjectApprover>(
+ new LocalHierarchicalRoleApprover(
+ hierarchicalRoleACLs, subject, action, acls.permissive()));
+ }
+
Future<Owned<ObjectApprover>> getNestedContainerObjectApprover(
const Option<authorization::Subject>& subject,
- const authorization::Action& action)
+ const authorization::Action& action) const
{
CHECK(action == authorization::LAUNCH_NESTED_CONTAINER ||
action == authorization::LAUNCH_NESTED_CONTAINER_SESSION);
@@ -747,24 +1011,56 @@ public:
return Owned<ObjectApprover>(new RejectingObjectApprover());
}
- if (action == authorization::LAUNCH_NESTED_CONTAINER ||
- action == authorization::LAUNCH_NESTED_CONTAINER_SESSION) {
- return getNestedContainerObjectApprover(subject, action);
- }
-
- Result<vector<GenericACL>> genericACLs = createGenericACLs(action, acls);
- if (genericACLs.isError()) {
- return Failure(genericACLs.error());
- }
+ switch (action) {
+ case authorization::LAUNCH_NESTED_CONTAINER:
+ case authorization::LAUNCH_NESTED_CONTAINER_SESSION: {
+ return getNestedContainerObjectApprover(subject, action);
+ }
+ case authorization::CREATE_VOLUME:
+ case authorization::RESERVE_RESOURCES:
+ case authorization::UPDATE_WEIGHT:
+ case authorization::VIEW_ROLE:
+ case authorization::GET_QUOTA:
+ case authorization::REGISTER_FRAMEWORK:
+ case authorization::UPDATE_QUOTA: {
+ return getHierarchicalRoleApprover(subject, action);
+ }
+ case authorization::ACCESS_MESOS_LOG:
+ case authorization::ACCESS_SANDBOX:
+ case authorization::ATTACH_CONTAINER_INPUT:
+ case authorization::ATTACH_CONTAINER_OUTPUT:
+ case authorization::DESTROY_VOLUME:
+ case authorization::GET_ENDPOINT_WITH_PATH:
+ case authorization::KILL_NESTED_CONTAINER:
+ case authorization::RUN_TASK:
+ case authorization::SET_LOG_LEVEL:
+ case authorization::TEARDOWN_FRAMEWORK:
+ case authorization::UNRESERVE_RESOURCES:
+ case authorization::VIEW_CONTAINER:
+ case authorization::VIEW_EXECUTOR:
+ case authorization::VIEW_FLAGS:
+ case authorization::VIEW_FRAMEWORK:
+ case authorization::VIEW_TASK:
+ case authorization::WAIT_NESTED_CONTAINER:
+ case authorization::REMOVE_NESTED_CONTAINER:
+ case authorization::UNKNOWN: {
+ Result<vector<GenericACL>> genericACLs =
+ createGenericACLs(action, acls);
+ if (genericACLs.isError()) {
+ return Failure(genericACLs.error());
+ }
+ if (genericACLs.isNone()) {
+ // If we could not create acls, we deny all objects.
+ return Owned<ObjectApprover>(new RejectingObjectApprover());
+ }
- if (genericACLs.isNone()) {
- // If we could not create acls, we deny all objects.
- return Owned<ObjectApprover>(new RejectingObjectApprover());
+ return Owned<ObjectApprover>(
+ new LocalAuthorizerObjectApprover(
+ genericACLs.get(), subject, action, acls.permissive()));
+ }
}
- return Owned<ObjectApprover>(
- new LocalAuthorizerObjectApprover(
- genericACLs.get(), subject, action, acls.permissive()));
+ UNREACHABLE();
}
private:
@@ -775,17 +1071,6 @@ private:
vector<GenericACL> acls_;
switch (action) {
- case authorization::REGISTER_FRAMEWORK:
- foreach (
- const ACL::RegisterFramework& acl, acls.register_frameworks()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
case authorization::TEARDOWN_FRAMEWORK:
foreach (
const ACL::TeardownFramework& acl, acls.teardown_frameworks()) {
@@ -807,16 +1092,6 @@ private:
}
return acls_;
- case authorization::RESERVE_RESOURCES:
- foreach (const ACL::ReserveResources& acl, acls.reserve_resources()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
case authorization::UNRESERVE_RESOURCES:
foreach (
const ACL::UnreserveResources& acl, acls.unreserve_resources()) {
@@ -828,16 +1103,6 @@ private:
}
return acls_;
- case authorization::CREATE_VOLUME:
- foreach (const ACL::CreateVolume& acl, acls.create_volumes()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
case authorization::DESTROY_VOLUME:
foreach (const ACL::DestroyVolume& acl, acls.destroy_volumes()) {
GenericACL acl_;
@@ -848,47 +1113,6 @@ private:
}
return acls_;
- case authorization::GET_QUOTA:
- foreach (const ACL::GetQuota& acl, acls.get_quotas()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
- case authorization::UPDATE_QUOTA: {
- foreach (const ACL::UpdateQuota& acl, acls.update_quotas()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
- }
- case authorization::VIEW_ROLE:
- foreach (const ACL::ViewRole& acl, acls.view_roles()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
- case authorization::UPDATE_WEIGHT:
- foreach (const ACL::UpdateWeight& acl, acls.update_weights()) {
- GenericACL acl_;
- acl_.subjects = acl.principals();
- acl_.objects = acl.roles();
-
- acls_.push_back(acl_);
- }
-
- return acls_;
case authorization::GET_ENDPOINT_WITH_PATH:
foreach (const ACL::GetEndpoint& acl, acls.get_endpoints()) {
GenericACL acl_;
@@ -1034,9 +1258,16 @@ private:
}
return acls_;
+ case authorization::REGISTER_FRAMEWORK:
+ case authorization::CREATE_VOLUME:
+ case authorization::RESERVE_RESOURCES:
+ case authorization::UPDATE_WEIGHT:
+ case authorization::VIEW_ROLE:
+ case authorization::GET_QUOTA:
+ case authorization::UPDATE_QUOTA:
case authorization::LAUNCH_NESTED_CONTAINER_SESSION:
case authorization::LAUNCH_NESTED_CONTAINER:
- return Error("Extracting ACLs for launching nested containers requires "
+ return Error("Extracting ACLs for " + stringify(action) + " requires "
"a specialized function");
case authorization::UNKNOWN:
// Cannot generate acls for an unknown action.
[2/2] mesos git commit: Added test for authorization of hierarchical
roles.
Posted by me...@apache.org.
Added test for authorization of hierarchical roles.
Adds tests for each of the actions which support hierarchical roles.
Review: https://reviews.apache.org/r/57474/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/d55148af
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/d55148af
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/d55148af
Branch: refs/heads/master
Commit: d55148afbe4c86dc97907abffcbf01dec7e8467a
Parents: d46d330
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Thu Apr 27 00:04:57 2017 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Thu Apr 27 00:05:39 2017 -0700
----------------------------------------------------------------------
src/tests/authorization_tests.cpp | 943 ++++++++++++++++++++++++++++++++-
1 file changed, 925 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/d55148af/src/tests/authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp
index 937a726..b59623f 100644
--- a/src/tests/authorization_tests.cpp
+++ b/src/tests/authorization_tests.cpp
@@ -885,6 +885,135 @@ TYPED_TEST(AuthorizationTest, PrincipalNotOfferedAnyRoleRestrictive)
}
+// Checks that the behavior of the authorizer is correct when using
+// hierarchical roles while registering frameworks.
+TYPED_TEST(AuthorizationTest, RegisterFrameworkHierarchical)
+{
+ ACLs acls;
+
+ {
+ // "elizabeth-ii" principal can register frameworks with role
+ // `king` and its nested ones.
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // "charles" principal can register frameworks with just roles
+ // nested under `king`.
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // "j-welby" principal register frameworks with just role 'king'.
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // No other principal can register frameworks in any role.
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
+ 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());
+
+ // `elizabeth-ii` has full permissions for the `king` role as well as all
+ // its nested roles. She should be able to register frameworks in the next
+ // three blocks.
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_framework_info()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()
+ ->mutable_framework_info()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()
+ ->mutable_framework_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_framework_info()->set_role("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_framework_info()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()
+ ->mutable_framework_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_framework_info()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()
+ ->mutable_framework_info()->set_role("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::REGISTER_FRAMEWORK);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()
+ ->mutable_framework_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+}
+
// Tests the authorization of ACLs used for dynamic reservation of resources.
TYPED_TEST(AuthorizationTest, Reserve)
{
@@ -906,6 +1035,31 @@ TYPED_TEST(AuthorizationTest, Reserve)
}
{
+ // Principal "elizabeth-ii" can reserve for the "king" role and its
+ // nested ones.
+ mesos::ACL::ReserveResources* acl = acls.add_reserve_resources();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // Principal "charles" can reserve for any role below the "king/" role.
+ // Not in "king" itself.
+ mesos::ACL::ReserveResources* acl = acls.add_reserve_resources();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // Principal "j-welby" can reserve only for the "king" role but not
+ // in any nested one.
+ mesos::ACL::ReserveResources* acl = acls.add_reserve_resources();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
// No other principals can reserve resources.
mesos::ACL::ReserveResources* acl = acls.add_reserve_resources();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
@@ -1025,6 +1179,87 @@ TYPED_TEST(AuthorizationTest, Reserve)
request.mutable_object()->mutable_resource()->set_role("ads");
AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
}
+
+ // `elizabeth-ii` has full permissions for the `king` role as well as all
+ // its nested roles. She should be able to reserve resources in the next
+ // three blocks.
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::RESERVE_RESOURCES);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
}
@@ -1230,6 +1465,38 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
}
{
+ // Principal "elizabeth-ii" can create volumes for the "king" role and its
+ // nested ones.
+ mesos::ACL::CreateVolume* acl = acls.add_create_volumes();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // Principal "charles" can create volumes for any role below the "king/"
+ // role. Not in "king" itself.
+ mesos::ACL::CreateVolume* acl = acls.add_create_volumes();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // Principal "j-welby" can create volumes only for the "king" role but
+ // not in any nested one.
+ mesos::ACL::CreateVolume* acl = acls.add_create_volumes();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // No other principals can create volumes.
+ mesos::ACL::CreateVolume* acl = acls.add_create_volumes();
+ acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
+ acl->mutable_roles()->set_type(mesos::ACL::Entity::NONE);
+ }
+
+ {
// No other principals can create volumes.
mesos::ACL::CreateVolume* acl = acls.add_create_volumes();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
@@ -1325,6 +1592,87 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
request.mutable_object()->mutable_resource()->set_role("panda");
AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
}
+
+ // `elizabeth-ii` has full permissions for the `king` role as well as all
+ // its nested roles. She should be able to create volumes in the next
+ // three blocks.
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::CREATE_VOLUME);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::CREATE_VOLUME);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::CREATE_VOLUME);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
}
@@ -1515,6 +1863,31 @@ TYPED_TEST(AuthorizationTest, UpdateQuota)
}
{
+ // Principal "elizabeth-ii" can update quotas 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 quotas 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 quotas 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 quotas.
mesos::ACL::UpdateQuota* acl = acls.add_update_quotas();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
@@ -1571,32 +1944,116 @@ TYPED_TEST(AuthorizationTest, UpdateQuota)
request.mutable_object()->mutable_quota_info()->set_role("prod");
AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
}
-}
-
-
-// This tests the authorization of requests to ViewFramework.
-TYPED_TEST(AuthorizationTest, ViewFramework)
-{
- // Setup ACLs.
- ACLs acls;
+ // `elizabeth-ii` has full permissions for the `king` role as well as all
+ // its nested roles. She should be able to update quotas in the next
+ // three blocks.
{
- // "foo" principal can view no frameworks.
- mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
- acl->mutable_principals()->add_values("foo");
- acl->mutable_users()->set_type(mesos::ACL::Entity::NONE);
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_quota_info()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
}
{
- // "bar" principal can see frameworks running under user "bar".
- mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
- acl->mutable_principals()->add_values("bar");
- acl->mutable_users()->add_values("bar");
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->mutable_quota_info()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
}
{
- // "ops" principal can see all frameworks.
- mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()
+ ->mutable_quota_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_quota_info()->set_role("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->mutable_quota_info()->set_role("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()
+ ->mutable_quota_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_quota_info()->set_role("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->mutable_quota_info()->set_role("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_QUOTA);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()
+ ->mutable_quota_info()->set_role("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+}
+
+
+// This tests the authorization of requests to ViewFramework.
+TYPED_TEST(AuthorizationTest, ViewFramework)
+{
+ // Setup ACLs.
+ ACLs acls;
+
+ {
+ // "foo" principal can view no frameworks.
+ mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
+ acl->mutable_principals()->add_values("foo");
+ acl->mutable_users()->set_type(mesos::ACL::Entity::NONE);
+ }
+
+ {
+ // "bar" principal can see frameworks running under user "bar".
+ mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
+ acl->mutable_principals()->add_values("bar");
+ acl->mutable_users()->add_values("bar");
+ }
+
+ {
+ // "ops" principal can see all frameworks.
+ mesos::ACL::ViewFramework* acl = acls.add_view_frameworks();
acl->mutable_principals()->add_values("ops");
acl->mutable_users()->set_type(mesos::ACL::Entity::ANY);
}
@@ -3941,6 +4398,31 @@ TYPED_TEST(AuthorizationTest, ViewRole)
}
{
+ // "elizabeth-ii" principal can view info about the `king` role and
+ // all its nested ones.
+ mesos::ACL::ViewRole* acl = acls.add_view_roles();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // "charles" can only view info about `king`'s nested roles, but not
+ // the role `king` itself.
+ mesos::ACL::ViewRole* acl = acls.add_view_roles();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // "j-welby" can only view info about the `king` role itself
+ // but not its nested roles.
+ mesos::ACL::ViewRole* acl = acls.add_view_roles();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
// No other principal can view any role.
mesos::ACL::ViewRole* acl = acls.add_view_roles();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
@@ -3980,6 +4462,431 @@ TYPED_TEST(AuthorizationTest, ViewRole)
AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
}
+
+ // `elizabeth-ii` has full permissions for the `king` role as well as all
+ // its nested roles. She should be able to view roles in the next
+ // three blocks.
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::VIEW_ROLE);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->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::VIEW_ROLE);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ {
+ authorization::Request request;
+ request.set_action(authorization::VIEW_ROLE);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+}
+
+
+// This tests the authorization of requests to UpdateWeight.
+TYPED_TEST(AuthorizationTest, UpdateWeight)
+{
+ // Setup ACLs.
+ ACLs acls;
+
+ {
+ // "foo" principal can update weights of `ANY` role.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ acl->mutable_principals()->add_values("foo");
+ acl->mutable_roles()->set_type(mesos::ACL::Entity::ANY);
+ }
+
+ {
+ // "bar" principal can update the weight of role `bar`.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ acl->mutable_principals()->add_values("bar");
+ acl->mutable_roles()->add_values("bar");
+ }
+
+ {
+ // "elizabeth-ii" principal can update weights of role `king` and
+ // its nested ones.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // "charles" principal can update weights of just roles nested
+ // under `king`.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // "j-welby" principal can update the weight of just role 'king'.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // No other principal can update any weights.
+ mesos::ACL::UpdateWeight* acl = acls.add_update_weights();
+ 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());
+
+ // Check that principal "foo" can update weights of any role.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("foo");
+
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "bar" cannot update the weight of role `foo`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("bar");
+ request.mutable_object()->set_value("foo");
+
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "bar" can update the weight of role `bar`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("bar");
+ request.mutable_object()->set_value("bar");
+
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can update the weight of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can update the weight of role
+ // `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can update the weight of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" cannot update the weight of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" can update the weight of role `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" can update the weight of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" can update the weight of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" cannot update the weight of role
+ // `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" cannot update the weight of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::UPDATE_WEIGHT);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+}
+
+
+// This tests the authorization of requests to GetQuota.
+TYPED_TEST(AuthorizationTest, GetQuota)
+{
+ // Setup ACLs.
+ ACLs acls;
+
+ {
+ // "foo" principal can get quotas of `ANY` role.
+ mesos::ACL::GetQuota* acl = acls.add_get_quotas();
+ acl->mutable_principals()->add_values("foo");
+ acl->mutable_roles()->set_type(mesos::ACL::Entity::ANY);
+ }
+
+ {
+ // "bar" principal can get the quota of role `bar`.
+ mesos::ACL::GetQuota* acl = acls.add_get_quotas();
+ acl->mutable_principals()->add_values("bar");
+ acl->mutable_roles()->add_values("bar");
+ }
+
+ {
+ // "elizabeth-ii" principal can view quotas of role `king` and its
+ // nested ones.
+ mesos::ACL::GetQuota* acl = acls.add_get_quotas();
+ acl->mutable_principals()->add_values("elizabeth-ii");
+ acl->mutable_roles()->add_values("king/%");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // "charles" principal can view quotas of just roles nested under `king`.
+ mesos::ACL::GetQuota* acl = acls.add_get_quotas();
+ acl->mutable_principals()->add_values("charles");
+ acl->mutable_roles()->add_values("king/%");
+ }
+
+ {
+ // "j-welby" principal can view the quotas of just role 'king'.
+ mesos::ACL::GetQuota* acl = acls.add_get_quotas();
+ acl->mutable_principals()->add_values("j-welby");
+ acl->mutable_roles()->add_values("king");
+ }
+
+ {
+ // No other principal can view any quota.
+ mesos::ACL::GetQuota* acl = acls.add_get_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());
+
+ // Check that principal "foo" can view quotas of any role.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("foo");
+
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "bar" cannot view quotas of role `foo`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("bar");
+ request.mutable_object()->set_value("foo");
+
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "bar" can view the quotas of role `bar`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("bar");
+ request.mutable_object()->set_value("bar");
+
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can view the quotas of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can view the quotas of role
+ // `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "elizabeth-ii" can view the quota of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("elizabeth-ii");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" cannot view the quota of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" can view the quota of role `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "charles" can view the quota of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("charles");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" can view the quota of role `king`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king");
+ AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" cannot view the quota of role
+ // `king/prince`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
+
+ // Check that principal "j-welby" cannot view the quota of role
+ // `king/prince/duke`.
+ {
+ authorization::Request request;
+ request.set_action(authorization::GET_QUOTA);
+ request.mutable_subject()->set_value("j-welby");
+ request.mutable_object()->set_value("king/prince/duke");
+ AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+ }
}
} // namespace tests {