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 2016/12/14 03:37:21 UTC

[1/4] mesos git commit: Added authorization actions VIEW_CONTAINERS and SET_LOG_LEVEL.

Repository: mesos
Updated Branches:
  refs/heads/master bf223671a -> 959b97e90


Added authorization actions VIEW_CONTAINERS and SET_LOG_LEVEL.

Adds the authorization action `VIEW_CONTAINERS` which takes an object
of type `FrameworkInfo` and `ExecutorInfo` and optionally a
`CommandInfo`.

It also adds the authorization action `SET_LOG_LEVEL` which takes no
object.

Includes testing for the ACLs and interface.

Review: https://reviews.apache.org/r/54535/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/9ec8b5e9
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/9ec8b5e9
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/9ec8b5e9

Branch: refs/heads/master
Commit: 9ec8b5e9256e3001cfbedb17ca6272dfe31db73a
Parents: bf22367
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Tue Dec 13 17:01:11 2016 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Tue Dec 13 17:01:11 2016 -0800

----------------------------------------------------------------------
 include/mesos/authorizer/acls.proto       |  24 ++++
 include/mesos/authorizer/authorizer.proto |   7 ++
 src/authorizer/local/authorizer.cpp       |  48 ++++++++
 src/tests/authorization_tests.cpp         | 152 +++++++++++++++++++++++++
 4 files changed, 231 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/9ec8b5e9/include/mesos/authorizer/acls.proto
----------------------------------------------------------------------
diff --git a/include/mesos/authorizer/acls.proto b/include/mesos/authorizer/acls.proto
index 3499cac..fd25e54 100644
--- a/include/mesos/authorizer/acls.proto
+++ b/include/mesos/authorizer/acls.proto
@@ -345,6 +345,28 @@ message ACL {
     // nested containers can be waited on.
     required Entity users = 2;
   }
+
+  // Which principals are authorized to see the container metadata of a
+  // container whose executor is running as the given operating system user.
+  message ViewContainer {
+    // Subjects: HTTP Username.
+    required Entity principals = 1;
+
+    // Objects: The list of operating system users (e.g., linux users) whose
+    // container metadata can viewed.
+    required Entity users = 2;
+  }
+
+  // Which principals are authorized to change the log level of the
+  // master/agent.
+  message SetLogLevel {
+    // Subjects: HTTP Username.
+    required Entity principals = 1;
+
+    // Objects: Given implicitly. Use Entity type ANY or NONE to allow or deny
+    // access.
+    required Entity level = 2;
+  }
 }
 
 
@@ -408,4 +430,6 @@ message ACLs {
       launch_nested_container_sessions_under_parent_with_user = 28;
   repeated ACL.AttachContainerInput attach_containers_input = 29;
   repeated ACL.AttachContainerOutput attach_containers_output = 30;
+  repeated ACL.ViewContainer view_containers = 31;
+  repeated ACL.SetLogLevel set_log_level = 32;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/9ec8b5e9/include/mesos/authorizer/authorizer.proto
----------------------------------------------------------------------
diff --git a/include/mesos/authorizer/authorizer.proto b/include/mesos/authorizer/authorizer.proto
index b7371cd..8b860a3 100644
--- a/include/mesos/authorizer/authorizer.proto
+++ b/include/mesos/authorizer/authorizer.proto
@@ -174,6 +174,13 @@ enum Action {
 
   // This action will set objects of type `ExecutorInfo` and `FrameworkInfo`.
   ATTACH_CONTAINER_OUTPUT = 24;
+
+  // This action will set objects of type `ExecutorInfo` and `FrameworkInfo`.
+  VIEW_CONTAINER = 25;
+
+  // This action will not fill in any object fields, since a principal is
+  // either allowed to change the log level or he is unauthorized.
+  SET_LOG_LEVEL = 26;
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/9ec8b5e9/src/authorizer/local/authorizer.cpp
----------------------------------------------------------------------
diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp
index 3b983d0..b98e1fc 100644
--- a/src/authorizer/local/authorizer.cpp
+++ b/src/authorizer/local/authorizer.cpp
@@ -487,6 +487,26 @@ public:
 
           break;
         }
+        case authorization::VIEW_CONTAINER: {
+          aclObject.set_type(mesos::ACL::Entity::ANY);
+
+          if (object->executor_info != nullptr &&
+              object->executor_info->command().has_user()) {
+            aclObject.add_values(object->executor_info->command().user());
+            aclObject.set_type(mesos::ACL::Entity::SOME);
+          } else if (object->framework_info != nullptr &&
+              object->framework_info->has_user()) {
+            aclObject.add_values(object->framework_info->user());
+            aclObject.set_type(mesos::ACL::Entity::SOME);
+          }
+
+          break;
+        }
+        case authorization::SET_LOG_LEVEL: {
+          aclObject.set_type(mesos::ACL::Entity::ANY);
+
+          break;
+        }
         case authorization::UNKNOWN:
           LOG(WARNING) << "Authorization for action '" << action_
                        << "' is not defined and therefore not authorized";
@@ -1005,6 +1025,28 @@ private:
 
         return acls_;
         break;
+      case authorization::SET_LOG_LEVEL:
+        foreach (const ACL::SetLogLevel& acl, acls.set_log_level()) {
+          GenericACL acl_;
+          acl_.subjects = acl.principals();
+          acl_.objects = acl.level();
+
+          acls_.push_back(acl_);
+        }
+
+        return acls_;
+        break;
+      case authorization::VIEW_CONTAINER:
+        foreach (const ACL::ViewContainer& acl, acls.view_containers()) {
+          GenericACL acl_;
+          acl_.subjects = acl.principals();
+          acl_.objects = acl.users();
+
+          acls_.push_back(acl_);
+        }
+
+        return acls_;
+        break;
       case authorization::LAUNCH_NESTED_CONTAINER_SESSION:
       case authorization::LAUNCH_NESTED_CONTAINER:
         return Error("Extracting ACLs for launching nested containers requires "
@@ -1079,6 +1121,12 @@ Option<Error> LocalAuthorizer::validate(const ACLs& acls)
     }
   }
 
+  foreach (const ACL::SetLogLevel& acl, acls.set_log_level()) {
+    if (acl.level().type() == ACL::Entity::SOME) {
+      return Error("acls.set_log_level type must be either NONE or ANY");
+    }
+  }
+
   foreach (const ACL::GetEndpoint& acl, acls.get_endpoints()) {
     if (acl.paths().type() == ACL::Entity::SOME) {
       foreach (const string& path, acl.paths().values()) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/9ec8b5e9/src/tests/authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp
index f70d60d..42edecc 100644
--- a/src/tests/authorization_tests.cpp
+++ b/src/tests/authorization_tests.cpp
@@ -1919,6 +1919,105 @@ TYPED_TEST(AuthorizationTest, ViewFramework)
 }
 
 
+// This tests the authorization of requests to ViewContainer.
+TYPED_TEST(AuthorizationTest, ViewContainer)
+{
+  // Setup ACLs.
+  ACLs acls;
+
+  {
+    // "foo" principal can view no containers.
+    mesos::ACL::ViewContainer* acl = acls.add_view_containers();
+    acl->mutable_principals()->add_values("foo");
+    acl->mutable_users()->set_type(mesos::ACL::Entity::NONE);
+  }
+
+  {
+    // "bar" principal can see containers running under user "bar".
+    mesos::ACL::ViewContainer* acl = acls.add_view_containers();
+    acl->mutable_principals()->add_values("bar");
+    acl->mutable_users()->add_values("bar");
+  }
+
+  {
+    // "ops" principal can see all containers.
+    mesos::ACL::ViewContainer* acl = acls.add_view_containers();
+    acl->mutable_principals()->add_values("ops");
+    acl->mutable_users()->set_type(mesos::ACL::Entity::ANY);
+  }
+
+  {
+    // No one else can view any containers.
+    mesos::ACL::ViewContainer* acl = acls.add_view_containers();
+    acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
+    acl->mutable_users()->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());
+
+  // Create FrameworkInfo with a generic user as object to be authorized.
+  FrameworkInfo frameworkInfo;
+  {
+    frameworkInfo.set_user("user");
+    frameworkInfo.set_name("f");
+  }
+
+  // Create FrameworkInfo with user "bar" as object to be authorized.
+  FrameworkInfo frameworkInfoBar;
+  {
+    frameworkInfoBar.set_user("bar");
+    frameworkInfoBar.set_name("f");
+  }
+
+  // Principal "foo" cannot view containers running with user "user".
+  {
+    authorization::Request request;
+    request.set_action(authorization::VIEW_CONTAINER);
+    request.mutable_subject()->set_value("foo");
+    request.mutable_object()->mutable_framework_info()->MergeFrom(
+        frameworkInfo);
+
+    AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+  }
+
+  // Principal "bar" cannot view containers running with user "user".
+  {
+    authorization::Request request;
+    request.set_action(authorization::VIEW_CONTAINER);
+    request.mutable_subject()->set_value("bar");
+    request.mutable_object()->mutable_framework_info()->MergeFrom(
+        frameworkInfo);
+
+    AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+  }
+
+  // Principal "ops" can view containers running with user "user".
+  {
+    authorization::Request request;
+    request.set_action(authorization::VIEW_CONTAINER);
+    request.mutable_subject()->set_value("ops");
+    request.mutable_object()->mutable_framework_info()->MergeFrom(
+        frameworkInfo);
+
+    AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+  }
+
+  // Principal "bar" can view containers running with user "bar".
+  {
+    authorization::Request request;
+    request.set_action(authorization::VIEW_CONTAINER);
+    request.mutable_subject()->set_value("bar");
+    request.mutable_object()->mutable_framework_info()->MergeFrom(
+        frameworkInfoBar);
+
+    AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+  }
+}
+
+
 // This tests the authorization of requests to ViewTasks.
 TYPED_TEST(AuthorizationTest, ViewTask)
 {
@@ -3825,6 +3924,59 @@ TYPED_TEST(AuthorizationTest, ViewFlags)
 }
 
 
+TYPED_TEST(AuthorizationTest, SetLogLevel)
+{
+  // Setup ACLs.
+  ACLs acls;
+
+  {
+    // "foo" principal can set log level.
+    mesos::ACL::SetLogLevel* acl = acls.add_set_log_level();
+    acl->mutable_principals()->add_values("foo");
+    acl->mutable_level()->set_type(mesos::ACL::Entity::ANY);
+  }
+
+  {
+    // Nobody else can set log level.
+    mesos::ACL::SetLogLevel* acl = acls.add_set_log_level();
+    acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
+    acl->mutable_level()->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());
+
+  {
+    authorization::Request request;
+    request.set_action(authorization::SET_LOG_LEVEL);
+    request.mutable_subject()->set_value("foo");
+
+    AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
+  }
+
+  {
+    authorization::Request request;
+    request.set_action(authorization::SET_LOG_LEVEL);
+    request.mutable_subject()->set_value("bar");
+    AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
+  }
+
+  // Test that no authorizer is created with invalid ACLs.
+  {
+    ACLs invalid;
+
+    mesos::ACL::SetLogLevel* acl = invalid.add_set_log_level();
+    acl->mutable_principals()->add_values("foo");
+    acl->mutable_level()->add_values("yoda");
+
+    Try<Authorizer*> create = TypeParam::create(parameterize(invalid));
+    EXPECT_ERROR(create);
+  }
+}
+
+
 // This tests the authorization of ACLs used for unreserve
 // operations on dynamically reserved resources.
 TYPED_TEST(AuthorizationTest, ValidateEndpoints)


[4/4] mesos git commit: Enabled authorization in SET_LOG_LEVEL API call.

Posted by me...@apache.org.
Enabled authorization in SET_LOG_LEVEL API call.

Adds the stub which allows only authorized users to change the log
level of Mesos using the HTTP API v1.

Review: https://reviews.apache.org/r/54662/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/959b97e9
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/959b97e9
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/959b97e9

Branch: refs/heads/master
Commit: 959b97e90b17ecefd9f4e4708288f30e94391e2c
Parents: 77b66ba
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Tue Dec 13 17:31:43 2016 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Tue Dec 13 17:34:39 2016 -0800

----------------------------------------------------------------------
 src/slave/http.cpp | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/959b97e9/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 6784fc5..56c2879 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -895,9 +895,36 @@ Future<Response> Slave::Http::setLoggingLevel(
   Duration duration =
     Nanoseconds(call.set_logging_level().duration().nanoseconds());
 
-  return dispatch(process::logging(), &Logging::set_level, level, duration)
-      .then([]() -> Response {
-        return OK();
+  Future<Owned<ObjectApprover>> approver;
+
+  if (slave->authorizer.isSome()) {
+    authorization::Subject subject;
+    if (principal.isSome()) {
+      subject.set_value(principal.get());
+    }
+
+    approver = slave->authorizer.get()->getObjectApprover(
+        subject, authorization::SET_LOG_LEVEL);
+  } else {
+    approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
+  }
+
+  return approver.then(
+      [level, duration](
+          const Owned<ObjectApprover>& approver) -> Future<Response> {
+        Try<bool> approved = approver->approved((ObjectApprover::Object()));
+
+        if (approved.isError()) {
+          return InternalServerError(approved.error());
+        } else if (!approved.get()) {
+          return Forbidden();
+        }
+
+        return dispatch(
+            process::logging(), &Logging::set_level, level, duration)
+          .then([]() -> Response {
+            return OK();
+          });
       });
 }
 


[2/4] mesos git commit: Enabled fine grained authorization for the getContainers API Call.

Posted by me...@apache.org.
Enabled fine grained authorization for the getContainers API Call.

Enables fine grained authorization for the v1 API call `GET_CONTAINERS`.

Review: https://reviews.apache.org/r/54538/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/982abdb5
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/982abdb5
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/982abdb5

Branch: refs/heads/master
Commit: 982abdb591f87ccf1748a735af4e2a8a84ab4dbe
Parents: 9ec8b5e
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Tue Dec 13 17:28:12 2016 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Tue Dec 13 17:28:24 2016 -0800

----------------------------------------------------------------------
 src/slave/http.cpp  | 148 ++++++++++++++++++++++++++++++++---------------
 src/slave/slave.hpp |   6 +-
 2 files changed, 105 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/982abdb5/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 8a71ead..0210379 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -1810,12 +1810,12 @@ Future<Response> Slave::Http::containers(
       principal)
     .then(defer(
         slave->self(),
-        [this, request](bool authorized) -> Future<Response> {
+        [this, request, principal](bool authorized) -> Future<Response> {
           if (!authorized) {
             return Forbidden();
           }
 
-          return _containers(request);
+          return _containers(request, principal);
         }));
 }
 
@@ -1823,54 +1823,90 @@ Future<Response> Slave::Http::containers(
 Future<Response> Slave::Http::getContainers(
     const agent::Call& call,
     ContentType acceptType,
-    const Option<string>& printcipal) const
+    const Option<string>& principal) const
 {
   CHECK_EQ(agent::Call::GET_CONTAINERS, call.type());
 
-  return __containers()
-      .then([acceptType](const Future<JSON::Array>& result)
-          -> Future<Response> {
-        if (!result.isReady()) {
-          LOG(WARNING) << "Could not collect container status and statistics: "
-                       << (result.isFailed()
-                            ? result.failure()
-                            : "Discarded");
-          return result.isFailed()
-            ? InternalServerError(result.failure())
-            : InternalServerError();
-        }
+  Future<Owned<ObjectApprover>> approver;
 
-        return OK(
-            serialize(
-                acceptType,
-                evolve<v1::agent::Response::GET_CONTAINERS>(result.get())),
-            stringify(acceptType));
-      });
+  if (slave->authorizer.isSome()) {
+    authorization::Subject subject;
+    if (principal.isSome()) {
+      subject.set_value(principal.get());
+    }
+
+    approver = slave->authorizer.get()->getObjectApprover(
+        subject, authorization::VIEW_CONTAINER);
+  } else {
+    approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
+  }
+
+  return approver.then(defer(slave->self(), [this](
+    const Owned<ObjectApprover>& approver) {
+        return __containers(approver);
+    })).then([acceptType](const Future<JSON::Array>& result)
+        -> Future<Response> {
+      if (!result.isReady()) {
+        LOG(WARNING) << "Could not collect container status and statistics: "
+                     << (result.isFailed()
+                          ? result.failure()
+                          : "Discarded");
+        return result.isFailed()
+          ? InternalServerError(result.failure())
+          : InternalServerError();
+      }
+
+      return OK(
+          serialize(
+              acceptType,
+              evolve<v1::agent::Response::GET_CONTAINERS>(result.get())),
+          stringify(acceptType));
+    });
 }
 
 
-Future<Response> Slave::Http::_containers(const Request& request) const
+Future<Response> Slave::Http::_containers(
+    const Request& request,
+    const Option<string>& principal) const
 {
-  return __containers()
-      .then([request](const Future<JSON::Array>& result) -> Future<Response> {
-        if (!result.isReady()) {
-          LOG(WARNING) << "Could not collect container status and statistics: "
-                       << (result.isFailed()
-                            ? result.failure()
-                            : "Discarded");
-
-          return result.isFailed()
-            ? InternalServerError(result.failure())
-            : InternalServerError();
-        }
+  Future<Owned<ObjectApprover>> approver;
 
-        return process::http::OK(
-            result.get(), request.url.query.get("jsonp"));
-      });
+  if (slave->authorizer.isSome()) {
+    authorization::Subject subject;
+    if (principal.isSome()) {
+      subject.set_value(principal.get());
+    }
+
+    approver = slave->authorizer.get()->getObjectApprover(
+        subject, authorization::VIEW_CONTAINER);
+  } else {
+    approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
+  }
+
+  return approver.then(defer(slave->self(), [this](
+    const Owned<ObjectApprover>& approver) {
+      return __containers(approver);
+     }))
+     .then([request](const Future<JSON::Array>& result) -> Future<Response> {
+       if (!result.isReady()) {
+         LOG(WARNING) << "Could not collect container status and statistics: "
+                      << (result.isFailed()
+                           ? result.failure()
+                           : "Discarded");
+
+         return result.isFailed()
+           ? InternalServerError(result.failure())
+           : InternalServerError();
+       }
+
+       return process::http::OK(
+           result.get(), request.url.query.get("jsonp"));
+     });
 }
 
 
-Future<JSON::Array> Slave::Http::__containers() const
+Future<JSON::Array> Slave::Http::__containers(
+    Option<Owned<ObjectApprover>> approver) const
 {
   Owned<list<JSON::Object>> metadata(new list<JSON::Object>());
   list<Future<ContainerStatus>> statusFutures;
@@ -1887,16 +1923,34 @@ Future<JSON::Array> Slave::Http::__containers() const
       const ExecutorInfo& info = executor->info;
       const ContainerID& containerId = executor->containerId;
 
-      JSON::Object entry;
-      entry.values["framework_id"] = info.framework_id().value();
-      entry.values["executor_id"] = info.executor_id().value();
-      entry.values["executor_name"] = info.name();
-      entry.values["source"] = info.source();
-      entry.values["container_id"] = containerId.value();
+      Try<bool> authorized = true;
 
-      metadata->push_back(entry);
-      statusFutures.push_back(slave->containerizer->status(containerId));
-      statsFutures.push_back(slave->containerizer->usage(containerId));
+      if (approver.isSome()) {
+        ObjectApprover::Object object;
+        object.executor_info = &info;
+        object.framework_info = &(framework->info);
+
+        authorized = approver.get()->approved(object);
+
+        if (authorized.isError()) {
+          LOG(WARNING) << "Error during ViewContainer authorization: "
+                       << authorized.error();
+          authorized = false;
+        }
+      }
+
+      if (authorized.get()) {
+        JSON::Object entry;
+        entry.values["framework_id"] = info.framework_id().value();
+        entry.values["executor_id"] = info.executor_id().value();
+        entry.values["executor_name"] = info.name();
+        entry.values["source"] = info.source();
+        entry.values["container_id"] = containerId.value();
+
+        metadata->push_back(entry);
+        statusFutures.push_back(slave->containerizer->status(containerId));
+        statsFutures.push_back(slave->containerizer->usage(containerId));
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/982abdb5/src/slave/slave.hpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp
index 059eb77..be72ba9 100644
--- a/src/slave/slave.hpp
+++ b/src/slave/slave.hpp
@@ -545,10 +545,12 @@ private:
 
     // Continuation for `/containers` endpoint
     process::Future<process::http::Response> _containers(
-        const process::http::Request& request) const;
+        const process::http::Request& request,
+        const Option<std::string>& principal) const;
 
     // Helper function to collect containers status and resource statistics.
-    process::Future<JSON::Array> __containers() const;
+    process::Future<JSON::Array> __containers(
+        Option<process::Owned<ObjectApprover>> approver) const;
 
     // Helper routines for endpoint authorization.
     Try<std::string> extractEndpoint(const process::http::URL& url) const;


[3/4] mesos git commit: Enabled authorization for the GET_FLAGS API Call.

Posted by me...@apache.org.
Enabled authorization for the GET_FLAGS API Call.

Adds the stub which allows for restriction of users when attempting
to access the `GET_FLAGS` API v1 call.

Review: https://reviews.apache.org/r/54661/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/77b66ba1
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/77b66ba1
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/77b66ba1

Branch: refs/heads/master
Commit: 77b66ba1b4826ce5f84f675ad2363b8bc3b5d73f
Parents: 982abdb
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Tue Dec 13 17:29:13 2016 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Tue Dec 13 17:30:26 2016 -0800

----------------------------------------------------------------------
 src/slave/http.cpp | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/77b66ba1/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 0210379..6784fc5 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -755,9 +755,36 @@ Future<Response> Slave::Http::getFlags(
 {
   CHECK_EQ(agent::Call::GET_FLAGS, call.type());
 
-  return OK(serialize(acceptType,
-                      evolve<v1::agent::Response::GET_FLAGS>(_flags())),
+  Future<Owned<ObjectApprover>> approver;
+
+  if (slave->authorizer.isSome()) {
+    authorization::Subject subject;
+    if (principal.isSome()) {
+      subject.set_value(principal.get());
+    }
+
+    approver = slave->authorizer.get()->getObjectApprover(
+        subject, authorization::VIEW_FLAGS);
+  } else {
+    approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
+  }
+
+  return approver.then(defer(slave->self(),
+      [this, acceptType](
+          const Owned<ObjectApprover>& approver) -> Future<Response> {
+        Try<bool> approved = approver->approved(ObjectApprover::Object());
+
+        if (approved.isError()) {
+          return InternalServerError(approved.error());
+        } else if (!approved.get()) {
+          return Forbidden();
+        }
+
+        return OK(
+            serialize(
+                acceptType, evolve<v1::agent::Response::GET_FLAGS>(_flags())),
             stringify(acceptType));
+      }));
 }