You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ar...@apache.org on 2018/03/14 17:10:18 UTC

[8/8] mesos git commit: Added the ObjectApprovers to which unifies authorization logic.

Added the ObjectApprovers to which unifies authorization logic.

Introduces the class `ObjectApprovers` which unifies the different
mechanisms used in Mesos in order to perform authorization.

This new class will supersede the `Acceptor` interfaces and their
logic.

Follow up patches will make use of this interface and remove
deprecated code.

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


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

Branch: refs/heads/master
Commit: dc9eaeb2667d154cba4cc0fa59825101b7987dc4
Parents: 28a20ba
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Mon Jan 22 15:22:04 2018 +0100
Committer: Alexander Rojas <al...@mesosphere.io>
Committed: Wed Mar 14 18:09:20 2018 +0100

----------------------------------------------------------------------
 src/common/http.cpp |  36 +++++++++++++++++
 src/common/http.hpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/dc9eaeb2/src/common/http.cpp
----------------------------------------------------------------------
diff --git a/src/common/http.cpp b/src/common/http.cpp
index 8d3a4ad..99d84cd 100644
--- a/src/common/http.cpp
+++ b/src/common/http.cpp
@@ -32,6 +32,7 @@
 #include <mesos/quota/quota.hpp>
 
 #include <process/authenticator.hpp>
+#include <process/collect.hpp>
 #include <process/dispatch.hpp>
 #include <process/future.hpp>
 #include <process/http.hpp>
@@ -861,6 +862,41 @@ const AuthorizationCallbacks createAuthorizationCallbacks(
   return callbacks;
 }
 
+Future<Owned<ObjectApprovers>> ObjectApprovers::create(
+    const Option<Authorizer*>& authorizer,
+    const Option<Principal>& principal,
+    std::initializer_list<authorization::Action> actions)
+{
+  // Ensures there are no repeated elements.
+  hashset<authorization::Action> _actions(actions);
+
+  Option<authorization::Subject> subject =
+    authorization::createSubject(principal);
+
+  if (authorizer.isNone()) {
+    hashmap<authorization::Action, Owned<ObjectApprover>> approvers;
+
+    foreach (authorization::Action action, _actions) {
+      approvers.put(
+          action,
+          Owned<ObjectApprover>(new AcceptingObjectApprover()));
+    }
+
+    return Owned<ObjectApprovers>(
+        new ObjectApprovers(std::move(approvers), principal));
+  }
+
+  return process::collect(lambda::map<std::list>(
+      [&](authorization::Action action) -> Future<Owned<ObjectApprover>> {
+        return authorizer.get()->getObjectApprover(subject, action);
+      },
+      _actions))
+    .then([=](const std::list<Owned<ObjectApprover>>& _approvers) {
+      return Owned<ObjectApprovers>(
+          new ObjectApprovers(lambda::zip(_actions, _approvers), principal));
+    });
+}
+
 
 bool approveViewFrameworkInfo(
     const Owned<ObjectApprover>& frameworksApprover,

http://git-wip-us.apache.org/repos/asf/mesos/blob/dc9eaeb2/src/common/http.hpp
----------------------------------------------------------------------
diff --git a/src/common/http.hpp b/src/common/http.hpp
index 750d3bf..d92ae2b 100644
--- a/src/common/http.hpp
+++ b/src/common/http.hpp
@@ -26,6 +26,7 @@
 
 #include <mesos/quota/quota.hpp>
 
+#include <process/authenticator.hpp>
 #include <process/future.hpp>
 #include <process/http.hpp>
 #include <process/owned.hpp>
@@ -37,6 +38,28 @@
 #include <stout/protobuf.hpp>
 #include <stout/unreachable.hpp>
 
+// TODO(benh): Remove this once we get C++14 as an enum should have a
+// default hash.
+namespace std {
+
+template <>
+struct hash<mesos::authorization::Action>
+{
+  typedef size_t result_type;
+
+  typedef mesos::authorization::Action argument_type;
+
+  result_type operator()(const argument_type& action) const
+  {
+    size_t seed = 0;
+    boost::hash_combine(
+        seed, static_cast<std::underlying_type<argument_type>::type>(action));
+    return seed;
+  }
+};
+
+} // namespace std {
+
 namespace mesos {
 
 class Attributes;
@@ -164,6 +187,85 @@ public:
 };
 
 
+class ObjectApprovers
+{
+public:
+  static process::Future<process::Owned<ObjectApprovers>> create(
+      const Option<Authorizer*>& authorizer,
+      const Option<process::http::authentication::Principal>& principal,
+      std::initializer_list<authorization::Action> actions);
+
+  template <authorization::Action action, typename... Args>
+  bool approved(const Args&... args)
+  {
+    if (!approvers.contains(action)) {
+      LOG(WARNING) << "Attempted to authorize "
+                   << (principal.isSome()
+                       ? "'" + stringify(principal.get()) + "'"
+                       : "")
+                   << " for unexpected action " << stringify(action);
+      return false;
+    }
+
+    Try<bool> approved = approvers[action]->approved(
+        ObjectApprover::Object(args...));
+
+    if (approved.isError()) {
+      // TODO(joerg84): Expose these errors back to the caller.
+      LOG(WARNING) << "Failed to authorize principal "
+                   << (principal.isSome()
+                       ? "'" + stringify(principal.get()) + "' "
+                       : "")
+                   << "for action " << stringify(action) << ": "
+                   << approved.error();
+      return false;
+    }
+
+    return approved.get();
+  }
+
+private:
+  ObjectApprovers(
+      hashmap<
+          authorization::Action,
+          process::Owned<ObjectApprover>>&& _approvers,
+      const Option<process::http::authentication::Principal>& _principal)
+    : approvers(std::move(_approvers)), principal(_principal) {}
+
+  hashmap<authorization::Action, process::Owned<ObjectApprover>> approvers;
+  Option<process::http::authentication::Principal> principal;
+};
+
+
+template <>
+inline bool ObjectApprovers::approved<authorization::VIEW_ROLE>(
+    const Resource& resource)
+{
+  // Necessary because recovered agents are presented in old format.
+  if (resource.has_role() && resource.role() != "*" &&
+      !approved<authorization::VIEW_ROLE>(resource.role())) {
+    return false;
+  }
+
+  // Reservations follow a path model where each entry is a child of the
+  // previous one. Therefore, to accept the resource the acceptor has to
+  // accept all entries.
+  foreach (Resource::ReservationInfo reservation, resource.reservations()) {
+    if (!approved<authorization::VIEW_ROLE>(reservation.role())) {
+      return false;
+    }
+  }
+
+  if (resource.has_allocation_info() &&
+      !approved<authorization::VIEW_ROLE>(
+          resource.allocation_info().role())) {
+    return false;
+  }
+
+  return true;
+}
+
+
 // Determines which objects will be accepted based on authorization.
 class AuthorizationAcceptor
 {
@@ -273,6 +375,7 @@ bool approveViewRole(
     const process::Owned<ObjectApprover>& rolesApprover,
     const std::string& role);
 
+
 // Authorizes resources in either the pre- or the post-reservation-refinement
 // formats.
 // TODO(arojas): Update this helper to only accept the