You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2016/04/15 23:00:02 UTC

[6/9] mesos git commit: Added AuthN for HTTP based frameworks.

Added AuthN for HTTP based frameworks.

This change adds AuthN support for HTTP based frameworks.

We allow AuthZ without AuthN for `/scheduler` endpoint. Also,
we ensure that `FrameworkInfo.principal` (if present) equals
the authenticated principal. We also allow a framework to
omit specifying the `FrameworkInfo.principal` in case
it is not interested in authorization or if it is disabled.
We do log a warning for this cases similar to what driver
based frameworks already do.

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


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

Branch: refs/heads/master
Commit: a080650aa0833b380ec86239360145688da9a4c1
Parents: 792b08d
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:26 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:26 2016 -0500

----------------------------------------------------------------------
 src/master/http.cpp       | 36 +++++++++++++++++++++++++++++-------
 src/master/master.cpp     |  6 ++++--
 src/master/master.hpp     |  3 ++-
 src/master/validation.cpp | 17 +++++++++++++++--
 src/master/validation.hpp |  4 +++-
 5 files changed, 53 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a080650a/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index b8a83b5..d83ccd3 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -334,7 +334,9 @@ string Master::Http::SCHEDULER_HELP()
 }
 
 
-Future<Response> Master::Http::scheduler(const Request& request) const
+Future<Response> Master::Http::scheduler(
+    const Request& request,
+    const Option<string>& principal) const
 {
   // TODO(vinod): Add metrics for rejected requests.
 
@@ -356,11 +358,6 @@ Future<Response> Master::Http::scheduler(const Request& request) const
     return ServiceUnavailable("Master has not finished recovery");
   }
 
-  if (master->flags.authenticate_frameworks) {
-    return Forbidden(
-        "HTTP schedulers are not supported when authentication is required");
-  }
-
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -403,7 +400,7 @@ Future<Response> Master::Http::scheduler(const Request& request) const
 
   scheduler::Call call = devolve(v1Call);
 
-  Option<Error> error = validation::scheduler::call::validate(call);
+  Option<Error> error = validation::scheduler::call::validate(call, principal);
 
   if (error.isSome()) {
     return BadRequest("Failed to validate Scheduler::Call: " +
@@ -431,6 +428,24 @@ Future<Response> Master::Http::scheduler(const Request& request) const
           "Subscribe calls should not include the 'Mesos-Stream-Id' header");
     }
 
+    const FrameworkInfo& frameworkInfo = call.subscribe().framework_info();
+
+    if (principal.isSome() && !frameworkInfo.has_principal()) {
+      // We allow an authenticated framework to not specify a principal
+      // in `FrameworkInfo` but we'd prefer to log a WARNING here. We also
+      // set `FrameworkInfo.principal` to the value of authenticated principal
+      // and use it for authorization later when it happens.
+      if (!frameworkInfo.has_principal()) {
+        LOG(WARNING)
+          << "Setting 'principal' in FrameworkInfo to '" << principal.get()
+          << "' because the framework authenticated with that principal but "
+          << "did not set it in FrameworkInfo";
+
+        call.mutable_subscribe()->mutable_framework_info()->set_principal(
+            principal.get());
+      }
+    }
+
     Pipe pipe;
     OK ok;
     ok.headers["Content-Type"] = stringify(responseContentType);
@@ -456,6 +471,13 @@ Future<Response> Master::Http::scheduler(const Request& request) const
     return BadRequest("Framework cannot be found");
   }
 
+  if (principal.isSome() && principal != framework->info.principal()) {
+    return BadRequest(
+        "Authenticated principal '" + principal.get() + "' does not "
+        "match principal '" + framework->info.principal() + "' set in "
+        "`FrameworkInfo`");
+  }
+
   if (!framework->connected) {
     return Forbidden("Framework is not subscribed");
   }

http://git-wip-us.apache.org/repos/asf/mesos/blob/a080650a/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 20101ee..210934b 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -945,10 +945,12 @@ void Master::initialize()
 
   // Setup HTTP routes.
   route("/api/v1/scheduler",
+        DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM,
         Http::SCHEDULER_HELP(),
-        [this](const process::http::Request& request) {
+        [this](const process::http::Request& request,
+               const Option<string>& principal) {
           Http::log(request);
-          return http.scheduler(request);
+          return http.scheduler(request, principal);
         });
   route("/create-volumes",
         DEFAULT_HTTP_AUTHENTICATION_REALM,

http://git-wip-us.apache.org/repos/asf/mesos/blob/a080650a/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index e7cb751..2dd0971 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1071,7 +1071,8 @@ private:
 
     // /api/v1/scheduler
     process::Future<process::http::Response> scheduler(
-        const process::http::Request& request) const;
+        const process::http::Request& request,
+        const Option<std::string>& principal) const;
 
     // /master/create-volumes
     process::Future<process::http::Response> createVolumes(

http://git-wip-us.apache.org/repos/asf/mesos/blob/a080650a/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index 0f7b9b9..2b91446 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -53,7 +53,9 @@ static bool invalidCharacter(char c)
 namespace scheduler {
 namespace call {
 
-Option<Error> validate(const mesos::scheduler::Call& call)
+Option<Error> validate(
+    const mesos::scheduler::Call& call,
+    const Option<string>& principal)
 {
   if (!call.IsInitialized()) {
     return Error("Not initialized: " + call.InitializationErrorString());
@@ -68,10 +70,21 @@ Option<Error> validate(const mesos::scheduler::Call& call)
       return Error("Expecting 'subscribe' to be present");
     }
 
-    if (call.subscribe().framework_info().id() != call.framework_id()) {
+    const FrameworkInfo& frameworkInfo = call.subscribe().framework_info();
+
+    if (frameworkInfo.id() != call.framework_id()) {
       return Error("'framework_id' differs from 'subscribe.framework_info.id'");
     }
 
+    if (principal.isSome() &&
+        frameworkInfo.has_principal() &&
+        principal != frameworkInfo.principal()) {
+      return Error(
+          "Authenticated principal '" + principal.get() + "' does not "
+          "match principal '" + frameworkInfo.principal() + "' set in "
+          "`FrameworkInfo`");
+    }
+
     return None();
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/a080650a/src/master/validation.hpp
----------------------------------------------------------------------
diff --git a/src/master/validation.hpp b/src/master/validation.hpp
index d1f2323..7fa1b89 100644
--- a/src/master/validation.hpp
+++ b/src/master/validation.hpp
@@ -42,7 +42,9 @@ namespace call {
 
 // Validates that a scheduler call is well-formed.
 // TODO(bmahler): Add unit tests.
-Option<Error> validate(const mesos::scheduler::Call& call);
+Option<Error> validate(
+    const mesos::scheduler::Call& call,
+    const Option<std::string>& principal = None());
 
 } // namespace call {
 } // namespace scheduler {