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 22:59:57 UTC

[1/9] mesos git commit: Simplified a conditional check while validating framework id.

Repository: mesos
Updated Branches:
  refs/heads/master 13e453789 -> 3a60e5e63


Simplified a conditional check while validating framework id.

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


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

Branch: refs/heads/master
Commit: 6519bf7c6e3790d767b12269805eacccf2315dff
Parents: 13e4537
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:58:59 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:58:59 2016 -0500

----------------------------------------------------------------------
 src/master/validation.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6519bf7c/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index 1342343..0f7b9b9 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -68,7 +68,7 @@ Option<Error> validate(const mesos::scheduler::Call& call)
       return Error("Expecting 'subscribe' to be present");
     }
 
-    if (!(call.subscribe().framework_info().id() == call.framework_id())) {
+    if (call.subscribe().framework_info().id() != call.framework_id()) {
       return Error("'framework_id' differs from 'subscribe.framework_info.id'");
     }
 


[4/9] mesos git commit: Added flags for authenticating HTTP frameworks to master.

Posted by vi...@apache.org.
Added flags for authenticating HTTP frameworks to master.

This change introduces two new flags `authenticate_http_frameworks`
and `http_framework_authenticators` to the master. This allows us
to selectively turn on/off framework authentication and decouple
them from authentication for operator endpoints.

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


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

Branch: refs/heads/master
Commit: 8996b6e5849d97f27f39ef7cef49d6d46404d683
Parents: 82e4364
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:17 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:17 2016 -0500

----------------------------------------------------------------------
 src/master/constants.hpp |  4 ++
 src/master/flags.cpp     | 20 ++++++++-
 src/master/flags.hpp     |  2 +
 src/master/master.cpp    | 98 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 123 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8996b6e5/src/master/constants.hpp
----------------------------------------------------------------------
diff --git a/src/master/constants.hpp b/src/master/constants.hpp
index 7c7cc25..e7e02a3 100644
--- a/src/master/constants.hpp
+++ b/src/master/constants.hpp
@@ -127,6 +127,10 @@ constexpr char DEFAULT_HTTP_AUTHENTICATOR[] = "basic";
 // Name of the default master HTTP authentication realm.
 constexpr char DEFAULT_HTTP_AUTHENTICATION_REALM[] = "mesos-master";
 
+// Name of the default authentication realm for HTTP frameworks.
+constexpr char DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM[] =
+  "mesos-master-scheduler";
+
 } // namespace master {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/8996b6e5/src/master/flags.cpp
----------------------------------------------------------------------
diff --git a/src/master/flags.cpp b/src/master/flags.cpp
index e522499..989bc98 100644
--- a/src/master/flags.cpp
+++ b/src/master/flags.cpp
@@ -203,7 +203,8 @@ mesos::internal::master::Flags::Flags()
   add(&Flags::authenticate_frameworks,
       "authenticate",
       "If `true`, only authenticated frameworks are allowed to register. If\n"
-      "`false`, unauthenticated frameworks are also allowed to register.",
+      "`false`, unauthenticated frameworks are also allowed to register. For\n"
+      "HTTP based frameworks use the `--authenticate_http_frameworks` flag.",
       false);
 
   add(&Flags::authenticate_slaves,
@@ -219,6 +220,12 @@ mesos::internal::master::Flags::Flags()
       "HTTP endpoints are also allowed.\n",
       false);
 
+  add(&Flags::authenticate_http_frameworks,
+      "authenticate_http_frameworks",
+      "If `true`, only authenticated HTTP frameworks are allowed to register.\n"
+      "If `false`, HTTP frameworks are not authenticated.",
+      false);
+
   add(&Flags::credentials,
       "credentials",
       "Path to a JSON-formatted file containing credentials.\n"
@@ -463,6 +470,17 @@ mesos::internal::master::Flags::Flags()
       "Currently there is no support for multiple HTTP authenticators.",
       DEFAULT_HTTP_AUTHENTICATOR);
 
+  add(&Flags::http_framework_authenticators,
+      "http_framework_authenticators",
+      "HTTP authenticator implementation to use when authenticating HTTP\n"
+      "frameworks. Use the \n"
+      "`" + string(DEFAULT_HTTP_AUTHENTICATOR) + "` authenticator or load an\n"
+      "alternate authenticator module using `--modules`.\n"
+      "Must be used in conjunction with `--http_authenticate_frameworks`.\n"
+      "\n"
+      "Currently there is no support for multiple HTTP framework\n"
+      "authenticators.");
+
   add(&Flags::max_completed_frameworks,
       "max_completed_frameworks",
       "Maximum number of completed frameworks to store in memory.",

http://git-wip-us.apache.org/repos/asf/mesos/blob/8996b6e5/src/master/flags.hpp
----------------------------------------------------------------------
diff --git a/src/master/flags.hpp b/src/master/flags.hpp
index 83bb908..e4cac1f 100644
--- a/src/master/flags.hpp
+++ b/src/master/flags.hpp
@@ -67,6 +67,7 @@ public:
   bool authenticate_frameworks;
   bool authenticate_slaves;
   bool authenticate_http;
+  bool authenticate_http_frameworks;
   Option<Path> credentials;
   Option<ACLs> acls;
   Option<Firewall> firewall_rules;
@@ -80,6 +81,7 @@ public:
   size_t max_slave_ping_timeouts;
   std::string authorizers;
   std::string http_authenticators;
+  Option<std::string> http_framework_authenticators;
   size_t max_completed_frameworks;
   size_t max_completed_tasks_per_framework;
   Option<std::string> master_contender;

http://git-wip-us.apache.org/repos/asf/mesos/blob/8996b6e5/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 37f4648..20101ee 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -434,12 +434,21 @@ void Master::initialize()
   } else {
     LOG(INFO) << "Master allowing unauthenticated frameworks to register";
   }
+
   if (flags.authenticate_slaves) {
     LOG(INFO) << "Master only allowing authenticated agents to register";
   } else {
     LOG(INFO) << "Master allowing unauthenticated agents to register";
   }
 
+  if (flags.authenticate_http_frameworks) {
+    LOG(INFO) << "Master only allowing authenticated HTTP frameworks to "
+              << "register";
+  } else {
+    LOG(INFO) << "Master allowing HTTP frameworks to register without "
+              << "authentication";
+  }
+
   // Load credentials.
   Option<Credentials> credentials;
   if (flags.credentials.isSome()) {
@@ -585,6 +594,95 @@ void Master::initialize()
     httpAuthenticator = None();
   }
 
+  if (flags.authenticate_http_frameworks) {
+    // The `--http_framework_authenticators` flag should always be set when HTTP
+    // framework authentication is enabled.
+    if (flags.http_framework_authenticators.isNone()) {
+      EXIT(EXIT_FAILURE)
+        << "Missing `--http_framework_authenticators` flag. This must be used "
+        << "in conjunction with `--authenticate_http_frameworks`";
+    }
+
+    vector<string> httpFrameworkAuthenticatorNames =
+      strings::split(flags.http_framework_authenticators.get(), ",");
+
+    // Passing an empty string into the `http_framework_authenticators`
+    // flag is considered an error.
+    if (httpFrameworkAuthenticatorNames.empty()) {
+      EXIT(EXIT_FAILURE) << "No HTTP framework authenticator specified";
+    }
+
+    if (httpFrameworkAuthenticatorNames.size() > 1) {
+      EXIT(EXIT_FAILURE) << "Multiple HTTP framework authenticators not "
+                         << "supported";
+    }
+
+    if (httpFrameworkAuthenticatorNames[0] != DEFAULT_HTTP_AUTHENTICATOR &&
+        !modules::ModuleManager::contains<authentication::Authenticator>(
+            httpFrameworkAuthenticatorNames[0])) {
+      EXIT(EXIT_FAILURE)
+        << "HTTP framework authenticator '"
+        << httpFrameworkAuthenticatorNames[0]
+        << "' not found. Check the spelling (compare to '"
+        << DEFAULT_HTTP_AUTHENTICATOR << "') or verify that the"
+        << " authenticator was loaded successfully (see --modules)";
+    }
+
+    Option<authentication::Authenticator*> httpFrameworkAuthenticator;
+
+    if (httpFrameworkAuthenticatorNames[0] == DEFAULT_HTTP_AUTHENTICATOR) {
+      if (credentials.isNone()) {
+        EXIT(EXIT_FAILURE)
+          << "No credentials provided for the default '"
+          << DEFAULT_HTTP_AUTHENTICATOR << "' HTTP framework authenticator";
+      }
+
+      LOG(INFO) << "Using default '" << DEFAULT_HTTP_AUTHENTICATOR
+                << "' HTTP framework authenticator";
+
+      Try<authentication::Authenticator*> authenticator =
+        BasicAuthenticatorFactory::create(
+            DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM,
+            credentials.get());
+
+      if (authenticator.isError()) {
+        EXIT(EXIT_FAILURE)
+          << "Could not create HTTP framework authenticator module '"
+          << httpFrameworkAuthenticatorNames[0] << "': "
+          << authenticator.error();
+      }
+
+      httpFrameworkAuthenticator = authenticator.get();
+    } else {
+      Try<authentication::Authenticator*> module =
+        modules::ModuleManager::create<authentication::Authenticator>(
+            httpFrameworkAuthenticatorNames[0]);
+
+      if (module.isError()) {
+        EXIT(EXIT_FAILURE)
+          << "Could not create HTTP framework authenticator module '"
+          << httpFrameworkAuthenticatorNames[0] << "': " << module.error();
+      }
+
+      LOG(INFO) << "Using '" << httpFrameworkAuthenticatorNames[0]
+                << "' HTTP framework authenticator";
+
+      httpFrameworkAuthenticator = module.get();
+    }
+
+    CHECK_SOME(httpFrameworkAuthenticator);
+
+    if (httpFrameworkAuthenticator.get() != NULL) {
+      // Ownership of the `httpFrameworkAuthenticator` is passed to libprocess.
+      process::http::authentication::setAuthenticator(
+          DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM,
+          Owned<authentication::Authenticator>(
+              httpFrameworkAuthenticator.get()));
+    }
+
+    httpFrameworkAuthenticator = None();
+  }
+
   if (authorizer.isSome()) {
     LOG(INFO) << "Authorization enabled";
   }


[5/9] mesos git commit: Added documentation around using AuthN for HTTP frameworks.

Posted by vi...@apache.org.
Added documentation around using AuthN for HTTP frameworks.

This change adds config docs around authenticating HTTP
frameworks using the newly introduced flags. Also added a
small note to the `authenticate` flag that this does not
work for HTTP based frameworks.

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


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

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

----------------------------------------------------------------------
 docs/configuration.md | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/792b08d5/docs/configuration.md
----------------------------------------------------------------------
diff --git a/docs/configuration.md b/docs/configuration.md
index ce51f26..cd97330 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -79,6 +79,17 @@ HTTP endpoints are also allowed. (default: false)
 </tr>
 <tr>
   <td>
+    --[no-]authenticate_http_frameworks
+  </td>
+  <td>
+If <code>true</code>, only authenticated HTTP based frameworks are allowed to
+register. If <code>false</code>, HTTP frameworks are not authenticated. For more
+about HTTP frameworks see the Scheduler HTTP API
+<a href="/documentation/latest/scheduler-http-api">documentation</a>. (default: false)
+  </td>
+</tr>
+<tr>
+  <td>
     --firewall_rules=VALUE
   </td>
   <td>
@@ -123,6 +134,20 @@ Currently there is no support for multiple HTTP authenticators. (default: basic)
 </tr>
 <tr>
   <td>
+    --http_framework_authenticators=VALUE
+  </td>
+  <td>
+HTTP authenticator implementation to use when authenticating HTTP frameworks.
+Use the <code>basic</code> authenticator or load an alternate HTTP authenticator
+module using <code>--modules</code>. This must be used in conjunction with
+<code>--authenticate_http_frameworks</code>.
+<p/>
+Currently there is no support for multiple HTTP authenticators.
+  </td>
+</tr>
+
+<tr>
+  <td>
     --ip=VALUE
   </td>
   <td>
@@ -463,7 +488,8 @@ load an alternate allocator module using <code>--modules</code>.
   </td>
   <td>
 If <code>true</code>, only authenticated frameworks are allowed to register. If
-<code>false</code>, unauthenticated frameworks are also allowed to register. (default: false)
+<code>false</code>, unauthenticated frameworks are also allowed to register. For
+HTTP based frameworks use the <code>--authenticate_http_frameworks</code> flag. (default: false)
   </td>
 </tr>
 <tr>


[7/9] mesos git commit: Added basic authentication scheme to the scheduler library.

Posted by vi...@apache.org.
Added basic authentication scheme to the scheduler library.

This change adds basic scheme AuthN support to the library.
It would be good to add support for additional schemes in the
future.

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


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

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

----------------------------------------------------------------------
 include/mesos/v1/scheduler.hpp |  6 +++++-
 src/scheduler/scheduler.cpp    | 24 ++++++++++++++++++++++--
 2 files changed, 27 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/e7f03a20/include/mesos/v1/scheduler.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/scheduler.hpp b/include/mesos/v1/scheduler.hpp
index 6603075..18e7a95 100644
--- a/include/mesos/v1/scheduler.hpp
+++ b/include/mesos/v1/scheduler.hpp
@@ -54,11 +54,14 @@ class MesosProcess; // Forward declaration.
 class Mesos
 {
 public:
+  // The credential will be used for authenticating with the master. Currently,
+  // only HTTP basic authentication is supported.
   Mesos(const std::string& master,
         ContentType contentType,
         const std::function<void()>& connected,
         const std::function<void()>& disconnected,
-        const std::function<void(const std::queue<Event>&)>& received);
+        const std::function<void(const std::queue<Event>&)>& received,
+        const Option<Credential>& credential);
 
   // Delete copy constructor.
   Mesos(const Mesos& other) = delete;
@@ -101,6 +104,7 @@ protected:
       const std::function<void()>& connected,
       const std::function<void()>& disconnected,
       const std::function<void(const std::queue<Event>&)>& received,
+      const Option<Credential>& credential,
       const Option<std::shared_ptr<mesos::master::detector::MasterDetector>>&
         detector);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/e7f03a20/src/scheduler/scheduler.cpp
----------------------------------------------------------------------
diff --git a/src/scheduler/scheduler.cpp b/src/scheduler/scheduler.cpp
index f9d54f9..c75e02c 100644
--- a/src/scheduler/scheduler.cpp
+++ b/src/scheduler/scheduler.cpp
@@ -130,11 +130,13 @@ public:
       const lambda::function<void()>& connected,
       const lambda::function<void()>& disconnected,
       const lambda::function<void(const queue<Event>&)>& received,
+      const Option<Credential>& _credential,
       const Option<shared_ptr<MasterDetector>>& _detector)
     : ProcessBase(ID::generate("scheduler")),
       state(DISCONNECTED),
       contentType(_contentType),
       callbacks {connected, disconnected, received},
+      credential(_credential),
       local(false)
   {
     GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -245,6 +247,14 @@ public:
     request.headers = {{"Accept", stringify(contentType)},
                        {"Content-Type", stringify(contentType)}};
 
+    // TODO(anand): Add support for other authentication schemes.
+
+    if (credential.isSome()) {
+      request.headers["Authorization"] =
+        "Basic " +
+        base64::encode(credential->principal() + ":" + credential->secret());
+    }
+
     CHECK_SOME(connections);
 
     Future<Response> response;
@@ -719,6 +729,7 @@ private:
   Option<SubscribedResponse> subscribed;
   ContentType contentType;
   Callbacks callbacks;
+  const Option<Credential> credential;
   Mutex mutex; // Used to serialize the callback invocations.
   bool local; // Whether or not we launched a local cluster.
   shared_ptr<MasterDetector> detector;
@@ -737,6 +748,7 @@ Mesos::Mesos(
     const lambda::function<void()>& connected,
     const lambda::function<void()>& disconnected,
     const lambda::function<void(const queue<Event>&)>& received,
+    const Option<Credential>& credential,
     const Option<shared_ptr<MasterDetector>>& detector)
 {
   process = new MesosProcess(
@@ -745,6 +757,7 @@ Mesos::Mesos(
       connected,
       disconnected,
       received,
+      credential,
       detector);
 
   spawn(process);
@@ -756,8 +769,15 @@ Mesos::Mesos(
     ContentType contentType,
     const lambda::function<void()>& connected,
     const lambda::function<void()>& disconnected,
-    const lambda::function<void(const queue<Event>&)>& received)
-  : Mesos(master, contentType, connected, disconnected, received, None()) {}
+    const lambda::function<void(const queue<Event>&)>& received,
+    const Option<Credential>& credential)
+  : Mesos(master,
+          contentType,
+          connected,
+          disconnected,
+          received,
+          credential,
+          None()) {}
 
 
 Mesos::~Mesos()


[9/9] mesos git commit: Fixed tests impacted by enabling AuthN for HTTP frameworks.

Posted by vi...@apache.org.
Fixed tests impacted by enabling AuthN for HTTP frameworks.

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


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

Branch: refs/heads/master
Commit: 3a60e5e63255a70e6170b29a2e07e271aa5d698f
Parents: 6348b5e
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:40 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:40 2016 -0500

----------------------------------------------------------------------
 src/tests/master_maintenance_tests.cpp |  20 ++--
 src/tests/master_quota_tests.cpp       |   2 +
 src/tests/mesos.cpp                    |   3 +
 src/tests/mesos.hpp                    |   1 +
 src/tests/scheduler_http_api_tests.cpp | 143 +++++++++-------------------
 src/tests/scheduler_tests.cpp          |  68 +++----------
 6 files changed, 71 insertions(+), 166 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/master_maintenance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_maintenance_tests.cpp b/src/tests/master_maintenance_tests.cpp
index 31d6c70..971c447 100644
--- a/src/tests/master_maintenance_tests.cpp
+++ b/src/tests/master_maintenance_tests.cpp
@@ -127,13 +127,6 @@ public:
     unavailability = createUnavailability(Clock::now());
   }
 
-  virtual master::Flags CreateMasterFlags()
-  {
-    master::Flags masterFlags = MesosTest::CreateMasterFlags();
-    masterFlags.authenticate_frameworks = false;
-    return masterFlags;
-  }
-
   virtual slave::Flags CreateSlaveFlags()
   {
     slave::Flags slaveFlags = MesosTest::CreateSlaveFlags();
@@ -380,8 +373,6 @@ TEST_F(MasterMaintenanceTest, FailToUnscheduleDeactivatedMachines)
 // slave is scheduled to go down for maintenance.
 TEST_F(MasterMaintenanceTest, PendingUnavailabilityTest)
 {
-  // Set up a master.
-  // NOTE: We don't use `StartMaster()` because we need to access these flags.
   master::Flags flags = CreateMasterFlags();
 
   Try<Owned<cluster::Master>> master = StartMaster(flags);
@@ -1085,8 +1076,8 @@ TEST_F(MasterMaintenanceTest, InverseOffers)
   Callbacks callbacks;
   Queue<Event> events;
 
-  // Set up a master.
   master::Flags masterFlags = CreateMasterFlags();
+
   Try<Owned<cluster::Master>> master = StartMaster(masterFlags);
   ASSERT_SOME(master);
 
@@ -1094,6 +1085,7 @@ TEST_F(MasterMaintenanceTest, InverseOffers)
   TestContainerizer containerizer(&exec);
 
   Owned<MasterDetector> detector = master.get()->createDetector();
+
   Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), &containerizer);
   ASSERT_SOME(slave);
 
@@ -1151,7 +1143,8 @@ TEST_F(MasterMaintenanceTest, InverseOffers)
       ContentType::PROTOBUF,
       lambda::bind(&Callbacks::connected, lambda::ref(callbacks)),
       lambda::bind(&Callbacks::disconnected, lambda::ref(callbacks)),
-      lambda::bind(&Callbacks::received, lambda::ref(callbacks), lambda::_1));
+      lambda::bind(&Callbacks::received, lambda::ref(callbacks), lambda::_1),
+      DEFAULT_V1_CREDENTIAL);
 
   AWAIT_READY(connected);
 
@@ -1394,8 +1387,6 @@ TEST_F(MasterMaintenanceTest, InverseOffersFilters)
   Callbacks callbacks;
   Queue<Event> events;
 
-  // Set up a master.
-  // NOTE: We don't use `StartMaster()` because we need to access these flags.
   master::Flags flags = CreateMasterFlags();
 
   Try<Owned<cluster::Master>> master = StartMaster(flags);
@@ -1495,7 +1486,8 @@ TEST_F(MasterMaintenanceTest, InverseOffersFilters)
       ContentType::PROTOBUF,
       lambda::bind(&Callbacks::connected, lambda::ref(callbacks)),
       lambda::bind(&Callbacks::disconnected, lambda::ref(callbacks)),
-      lambda::bind(&Callbacks::received, lambda::ref(callbacks), lambda::_1));
+      lambda::bind(&Callbacks::received, lambda::ref(callbacks), lambda::_1),
+      DEFAULT_V1_CREDENTIAL);
 
   AWAIT_READY(connected);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/master_quota_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_quota_tests.cpp b/src/tests/master_quota_tests.cpp
index e4a65bf..9ce7e2e 100644
--- a/src/tests/master_quota_tests.cpp
+++ b/src/tests/master_quota_tests.cpp
@@ -1050,6 +1050,7 @@ TEST_F(MasterQuotaTest, NoAuthenticationNoAuthorization)
   master::Flags masterFlags = CreateMasterFlags();
   masterFlags.acls = ACLs();
   masterFlags.authenticate_http = false;
+  masterFlags.authenticate_http_frameworks = false;
   masterFlags.credentials = None();
 
   Try<Owned<cluster::Master>> master = StartMaster(&allocator, masterFlags);
@@ -1288,6 +1289,7 @@ TEST_F(MasterQuotaTest, AuthorizeQuotaRequestsWithoutPrincipal)
   master::Flags masterFlags = CreateMasterFlags();
   masterFlags.acls = acls;
   masterFlags.authenticate_http = false;
+  masterFlags.authenticate_http_frameworks = false;
   masterFlags.credentials = None();
 
   Try<Owned<cluster::Master>> master = StartMaster(masterFlags);

http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/mesos.cpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.cpp b/src/tests/mesos.cpp
index 1b7a8fd..b5937af 100644
--- a/src/tests/mesos.cpp
+++ b/src/tests/mesos.cpp
@@ -95,6 +95,9 @@ master::Flags MesosTest::CreateMasterFlags()
   flags.authenticate_frameworks = true;
   flags.authenticate_slaves = true;
 
+  flags.authenticate_http_frameworks = true;
+  flags.http_framework_authenticators = "basic";
+
   // Create a default credentials file.
   const string& path = path::join(os::getcwd(), "credentials");
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index 20370a2..e4b63d4 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -986,6 +986,7 @@ public:
           lambda::bind(&TestMesos<Mesos, Event>::events,
                        this,
                        lambda::_1),
+          DEFAULT_V1_CREDENTIAL,
           detector),
       scheduler(_scheduler) {}
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/scheduler_http_api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/scheduler_http_api_tests.cpp b/src/tests/scheduler_http_api_tests.cpp
index f314d0a..85e55e2 100644
--- a/src/tests/scheduler_http_api_tests.cpp
+++ b/src/tests/scheduler_http_api_tests.cpp
@@ -59,12 +59,12 @@ using process::Owned;
 using process::PID;
 
 using process::http::BadRequest;
-using process::http::Forbidden;
 using process::http::MethodNotAllowed;
 using process::http::NotAcceptable;
 using process::http::OK;
 using process::http::Pipe;
 using process::http::Response;
+using process::http::Unauthorized;
 using process::http::UnsupportedMediaType;
 
 using recordio::Decoder;
@@ -130,10 +130,7 @@ INSTANTIATE_TEST_CASE_P(
 
 TEST_F(SchedulerHttpApiTest, AuthenticationRequired)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = true;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Future<Response> response = process::http::post(
@@ -142,18 +139,14 @@ TEST_F(SchedulerHttpApiTest, AuthenticationRequired)
       None(),
       None());
 
-  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Forbidden().status, response);
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
 }
 
 
 // TODO(anand): Add additional tests for validation.
 TEST_F(SchedulerHttpApiTest, NoContentType)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   // Expect a BadRequest when 'Content-Type' is omitted.
@@ -163,7 +156,7 @@ TEST_F(SchedulerHttpApiTest, NoContentType)
   Future<Response> response = process::http::post(
       master.get()->pid,
       "api/v1/scheduler",
-      None(),
+      createBasicAuthHeaders(DEFAULT_CREDENTIAL),
       None());
 
   AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response);
@@ -174,17 +167,13 @@ TEST_F(SchedulerHttpApiTest, NoContentType)
 // into a valid protobuf resulting in a BadRequest.
 TEST_F(SchedulerHttpApiTest, ValidJsonButInvalidProtobuf)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   JSON::Object object;
   object.values["string"] = "valid_json";
 
-  process::http::Headers headers;
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = APPLICATION_JSON;
 
   Future<Response> response = process::http::post(
@@ -202,17 +191,14 @@ TEST_F(SchedulerHttpApiTest, ValidJsonButInvalidProtobuf)
 // into a valid protobuf resulting in a BadRequest.
 TEST_P(SchedulerHttpApiTest, MalformedContent)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   const string body = "MALFORMED_CONTENT";
 
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   Future<Response> response = process::http::post(
@@ -230,15 +216,12 @@ TEST_P(SchedulerHttpApiTest, MalformedContent)
 // should result in a 415 (UnsupportedMediaType) response.
 TEST_P(SchedulerHttpApiTest, UnsupportedContentMediaType)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   Call call;
@@ -265,11 +248,7 @@ TEST_P(SchedulerHttpApiTest, UnsupportedContentMediaType)
 // call request.
 TEST_P(SchedulerHttpApiTest, Subscribe)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Call call;
@@ -280,7 +259,8 @@ TEST_P(SchedulerHttpApiTest, Subscribe)
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   Future<Response> response = process::http::streaming::post(
@@ -388,11 +368,7 @@ TEST_P(SchedulerHttpApiTest, RejectFrameworkWithInvalidRole)
 // includes a stream ID header with a subscribe call.
 TEST_P(SchedulerHttpApiTest, SubscribeWithStreamId)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Call call;
@@ -403,7 +379,8 @@ TEST_P(SchedulerHttpApiTest, SubscribeWithStreamId)
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
   headers["Mesos-Stream-Id"] = UUID::random().toString();
 
@@ -422,11 +399,7 @@ TEST_P(SchedulerHttpApiTest, SubscribeWithStreamId)
 // e.g. after a ZK blip.
 TEST_P(SchedulerHttpApiTest, SubscribedOnRetry)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Call call;
@@ -437,7 +410,8 @@ TEST_P(SchedulerHttpApiTest, SubscribedOnRetry)
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   auto deserializer = lambda::bind(
@@ -511,17 +485,12 @@ TEST_P(SchedulerHttpApiTest, SubscribedOnRetry)
 // scheduler to HTTP scheduler.
 TEST_P(SchedulerHttpApiTest, UpdatePidToHttpScheduler)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   v1::FrameworkInfo frameworkInfo = DEFAULT_V1_FRAMEWORK_INFO;
   frameworkInfo.set_failover_timeout(Weeks(2).secs());
 
-  // Start the scheduler without credentials.
   MockScheduler sched;
   StandaloneMasterDetector detector(master.get()->pid);
   TestingMesosSchedulerDriver driver(&sched, &detector, devolve(frameworkInfo));
@@ -555,7 +524,8 @@ TEST_P(SchedulerHttpApiTest, UpdatePidToHttpScheduler)
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   Future<Response> response = process::http::streaming::post(
@@ -602,11 +572,7 @@ TEST_P(SchedulerHttpApiTest, UpdatePidToHttpScheduler)
 // framework to PID.
 TEST_P(SchedulerHttpApiTest, UpdateHttpToPidScheduler)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   v1::FrameworkInfo frameworkInfo = DEFAULT_V1_FRAMEWORK_INFO;
@@ -619,7 +585,8 @@ TEST_P(SchedulerHttpApiTest, UpdateHttpToPidScheduler)
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   Future<Response> response = process::http::streaming::post(
@@ -657,10 +624,9 @@ TEST_P(SchedulerHttpApiTest, UpdateHttpToPidScheduler)
 
   ASSERT_EQ(Event::HEARTBEAT, event.get().get().type());
 
-  // Start PID based scheduler without credentials.
   MockScheduler sched;
   MesosSchedulerDriver driver(
-      &sched, devolve(frameworkInfo), master.get()->pid);
+      &sched, devolve(frameworkInfo), master.get()->pid, DEFAULT_CREDENTIAL);
 
   Future<FrameworkID> frameworkId;
   EXPECT_CALL(sched, registered(&driver, _, _))
@@ -678,17 +644,13 @@ TEST_P(SchedulerHttpApiTest, UpdateHttpToPidScheduler)
 
 TEST_P(SchedulerHttpApiTest, NotAcceptable)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
 
-  process::http::Headers headers;
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = "foo";
 
   // Only subscribe needs to 'Accept' json or protobuf.
@@ -711,11 +673,7 @@ TEST_P(SchedulerHttpApiTest, NotAcceptable)
 
 TEST_P(SchedulerHttpApiTest, NoAcceptHeader)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   // Retrieve the parameter passed as content type to this test.
@@ -723,7 +681,7 @@ TEST_P(SchedulerHttpApiTest, NoAcceptHeader)
 
   // No 'Accept' header leads to all media types considered
   // acceptable. JSON will be chosen by default.
-  process::http::Headers headers;
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
 
   // Only subscribe needs to 'Accept' json or protobuf.
   Call call;
@@ -746,14 +704,10 @@ TEST_P(SchedulerHttpApiTest, NoAcceptHeader)
 
 TEST_P(SchedulerHttpApiTest, DefaultAccept)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
-  process::http::Headers headers;
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = "*/*";
 
   // Only subscribe needs to 'Accept' json or protobuf.
@@ -780,15 +734,14 @@ TEST_P(SchedulerHttpApiTest, DefaultAccept)
 
 TEST_F(SchedulerHttpApiTest, GetRequest)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Future<Response> response = process::http::get(
       master.get()->pid,
-      "api/v1/scheduler");
+      "api/v1/scheduler",
+      None(),
+      createBasicAuthHeaders(DEFAULT_CREDENTIAL));
 
   AWAIT_READY(response);
   AWAIT_EXPECT_RESPONSE_STATUS_EQ(MethodNotAllowed({"POST"}).status, response);
@@ -799,16 +752,13 @@ TEST_F(SchedulerHttpApiTest, GetRequest)
 // when a teardown call is made without including a stream ID header.
 TEST_P(SchedulerHttpApiTest, TeardownWithoutStreamId)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   v1::FrameworkID frameworkId;
@@ -873,16 +823,13 @@ TEST_P(SchedulerHttpApiTest, TeardownWithoutStreamId)
 // when a teardown call is made with an incorrect stream ID header.
 TEST_P(SchedulerHttpApiTest, TeardownWrongStreamId)
 {
-  // HTTP schedulers cannot yet authenticate.
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   // Retrieve the parameter passed as content type to this test.
   const string contentType = GetParam();
-  process::http::Headers headers;
+
+  process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   headers["Accept"] = contentType;
 
   v1::FrameworkID frameworkId;

http://git-wip-us.apache.org/repos/asf/mesos/blob/3a60e5e6/src/tests/scheduler_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/scheduler_tests.cpp b/src/tests/scheduler_tests.cpp
index b630944..d9cc3fd 100644
--- a/src/tests/scheduler_tests.cpp
+++ b/src/tests/scheduler_tests.cpp
@@ -99,10 +99,7 @@ INSTANTIATE_TEST_CASE_P(
 // This test verifies that a scheduler can subscribe with the master.
 TEST_P(SchedulerTest, Subscribe)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -145,10 +142,7 @@ TEST_P(SchedulerTest, Subscribe)
 // failing over to another instance.
 TEST_P(SchedulerTest, SchedulerFailover)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -241,10 +235,7 @@ TEST_P(SchedulerTest, SchedulerFailover)
 // This test verifies that the scheduler can subscribe after a master failover.
 TEST_P(SchedulerTest, MasterFailover)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -290,7 +281,7 @@ TEST_P(SchedulerTest, MasterFailover)
 
   // Failover the master.
   master->reset();
-  master = StartMaster(flags);
+  master = StartMaster();
   ASSERT_SOME(master);
 
   AWAIT_READY(disconnected);
@@ -326,10 +317,7 @@ TEST_P(SchedulerTest, MasterFailover)
 
 TEST_P(SchedulerTest, TaskRunning)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -453,10 +441,7 @@ TEST_P(SchedulerTest, TaskRunning)
 
 TEST_P(SchedulerTest, ReconcileTask)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -585,10 +570,7 @@ TEST_P(SchedulerTest, ReconcileTask)
 
 TEST_P(SchedulerTest, KillTask)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -734,10 +716,7 @@ TEST_P(SchedulerTest, KillTask)
 
 TEST_P(SchedulerTest, ShutdownExecutor)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -866,10 +845,7 @@ TEST_P(SchedulerTest, ShutdownExecutor)
 
 TEST_P(SchedulerTest, Teardown)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -985,7 +961,6 @@ TEST_P(SchedulerTest, Teardown)
 TEST_P(SchedulerTest, Decline)
 {
   master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
 
   Try<Owned<cluster::Master>> master = StartMaster(flags);
   ASSERT_SOME(master);
@@ -1080,10 +1055,7 @@ TEST_P(SchedulerTest, Decline)
 
 TEST_P(SchedulerTest, Revive)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Owned<MasterDetector> detector = master.get()->createDetector();
@@ -1182,10 +1154,7 @@ TEST_P(SchedulerTest, Revive)
 
 TEST_P(SchedulerTest, Suppress)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   Owned<MasterDetector> detector = master.get()->createDetector();
@@ -1301,10 +1270,7 @@ TEST_P(SchedulerTest, Suppress)
 
 TEST_P(SchedulerTest, Message)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -1431,10 +1397,7 @@ TEST_P(SchedulerTest, Message)
 
 TEST_P(SchedulerTest, Request)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();
@@ -1497,10 +1460,7 @@ TEST_P(SchedulerTest, Request)
 // the master.
 TEST_P(SchedulerTest, SchedulerReconnect)
 {
-  master::Flags flags = CreateMasterFlags();
-  flags.authenticate_frameworks = false;
-
-  Try<Owned<cluster::Master>> master = StartMaster(flags);
+  Try<Owned<cluster::Master>> master = StartMaster();
   ASSERT_SOME(master);
 
   auto scheduler = std::make_shared<MockV1HTTPScheduler>();


[2/9] mesos git commit: Explicitly set `FrameworkInfo.principal` if AuthN is enabled.

Posted by vi...@apache.org.
Explicitly set `FrameworkInfo.principal` if AuthN is enabled.

This change explicitly sets `FrameworkInfo.principal` if
AuthN is enabled for old driver based frameworks. The
value gets defaulted to the authenticated principal (if missing).

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


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

Branch: refs/heads/master
Commit: 81793f42dff29d04cafdefba90979908a6406df1
Parents: 6519bf7
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:05 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:05 2016 -0500

----------------------------------------------------------------------
 src/master/master.cpp | 42 ++++++++++++++++++++++++------------------
 src/master/master.hpp |  6 ++++--
 2 files changed, 28 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/81793f42/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index f9962a9..963cc29 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -2142,25 +2142,26 @@ void Master::subscribe(
   // Need to disambiguate for the compiler.
   void (Master::*_subscribe)(
       HttpConnection,
-      const scheduler::Call::Subscribe&,
+      const FrameworkInfo&,
+      bool,
       const Future<bool>&) = &Self::_subscribe;
 
   authorizeFramework(frameworkInfo)
     .onAny(defer(self(),
                  _subscribe,
                  http,
-                 subscribe,
+                 frameworkInfo,
+                 subscribe.force(),
                  lambda::_1));
 }
 
 
 void Master::_subscribe(
     HttpConnection http,
-    const scheduler::Call::Subscribe& subscribe,
+    const FrameworkInfo& frameworkInfo,
+    bool force,
     const Future<bool>& authorized)
 {
-  const FrameworkInfo& frameworkInfo = subscribe.framework_info();
-
   CHECK(!authorized.isDiscarded());
 
   Option<Error> authorizationError = None();
@@ -2286,7 +2287,7 @@ void Master::subscribe(
     const UPID& from,
     const scheduler::Call::Subscribe& subscribe)
 {
-  const FrameworkInfo& frameworkInfo = subscribe.framework_info();
+  FrameworkInfo frameworkInfo = subscribe.framework_info();
 
   // Update messages_{re}register_framework accordingly.
   if (!frameworkInfo.has_id() || frameworkInfo.id() == "") {
@@ -2363,36 +2364,41 @@ void Master::subscribe(
             << " framework '" << frameworkInfo.name() << "' at " << from;
 
   // We allow an authenticated framework to not specify a principal
-  // in FrameworkInfo but we'd prefer if it did so we log a WARNING
-  // here when it happens.
+  // 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() && authenticated.contains(from)) {
-    LOG(WARNING) << "Framework at " << from
-                 << " (authenticated as '" << authenticated[from] << "')"
-                 << " does not set 'principal' in FrameworkInfo";
+    LOG(WARNING)
+      << "Setting 'principal' in FrameworkInfo to '" << authenticated[from]
+      << "' because the framework authenticated with that principal but did "
+      << "not set it in FrameworkInfo";
+
+    frameworkInfo.set_principal(authenticated[from]);
   }
 
   // Need to disambiguate for the compiler.
   void (Master::*_subscribe)(
       const UPID&,
-      const scheduler::Call::Subscribe&,
+      const FrameworkInfo&,
+      bool,
       const Future<bool>&) = &Self::_subscribe;
 
   authorizeFramework(frameworkInfo)
     .onAny(defer(self(),
                  _subscribe,
                  from,
-                 subscribe,
+                 frameworkInfo,
+                 subscribe.force(),
                  lambda::_1));
 }
 
 
 void Master::_subscribe(
     const UPID& from,
-    const scheduler::Call::Subscribe& subscribe,
+    const FrameworkInfo& frameworkInfo,
+    bool force,
     const Future<bool>& authorized)
 {
-  const FrameworkInfo& frameworkInfo = subscribe.framework_info();
-
   CHECK(!authorized.isDiscarded());
 
   Option<Error> authorizationError = None();
@@ -2480,7 +2486,7 @@ void Master::_subscribe(
       CHECK_NOTNULL(frameworks.registered[frameworkInfo.id()]);
 
     // Test for the error case first.
-    if ((framework->pid != from) && !subscribe.force()) {
+    if ((framework->pid != from) && !force) {
       LOG(ERROR) << "Disallowing subscription attempt of"
                  << " framework " << *framework
                  << " because it is not expected from " << from;
@@ -2501,7 +2507,7 @@ void Master::_subscribe(
 
     framework->reregisteredTime = Clock::now();
 
-    if (subscribe.force()) {
+    if (force) {
       // TODO(vinod): Now that the scheduler pid is unique we don't
       // need to call 'failoverFramework()' if the pid hasn't changed
       // (i.e., duplicate message). Instead we can just send the

http://git-wip-us.apache.org/repos/asf/mesos/blob/81793f42/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 1f480f0..e7cb751 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -853,7 +853,8 @@ private:
 
   void _subscribe(
       HttpConnection http,
-      const scheduler::Call::Subscribe& subscribe,
+      const FrameworkInfo& frameworkInfo,
+      bool force,
       const process::Future<bool>& authorized);
 
   void subscribe(
@@ -862,7 +863,8 @@ private:
 
   void _subscribe(
       const process::UPID& from,
-      const scheduler::Call::Subscribe& subscribe,
+      const FrameworkInfo& frameworkInfo,
+      bool force,
       const process::Future<bool>& authorized);
 
   void teardown(Framework* framework);


[8/9] mesos git commit: Added `None()` for credentials when creating scheduler lib.

Posted by vi...@apache.org.
Added `None()` for credentials when creating scheduler lib.

This change defaults the credentials argument to \`None()\` for
command scheduler/example HTTP framework/long lived framework when
creating the scheduler library object.

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


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

Branch: refs/heads/master
Commit: 6348b5e49cbe3074cae0c1ffba4bbf724caa79a6
Parents: e7f03a2
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:36 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:36 2016 -0500

----------------------------------------------------------------------
 src/cli/execute.cpp                   | 3 ++-
 src/examples/long_lived_framework.cpp | 3 ++-
 src/examples/test_http_framework.cpp  | 3 ++-
 3 files changed, 6 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6348b5e4/src/cli/execute.cpp
----------------------------------------------------------------------
diff --git a/src/cli/execute.cpp b/src/cli/execute.cpp
index 7cbe6a4..f70d9e1 100644
--- a/src/cli/execute.cpp
+++ b/src/cli/execute.cpp
@@ -240,7 +240,8 @@ protected:
       mesos::ContentType::PROTOBUF,
       process::defer(self(), &Self::connected),
       process::defer(self(), &Self::disconnected),
-      process::defer(self(), &Self::received, lambda::_1)));
+      process::defer(self(), &Self::received, lambda::_1),
+      None()));
   }
 
   void connected()

http://git-wip-us.apache.org/repos/asf/mesos/blob/6348b5e4/src/examples/long_lived_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/long_lived_framework.cpp b/src/examples/long_lived_framework.cpp
index 853e676..c696ccb 100644
--- a/src/examples/long_lived_framework.cpp
+++ b/src/examples/long_lived_framework.cpp
@@ -125,7 +125,8 @@ protected:
       mesos::ContentType::PROTOBUF,
       process::defer(self(), &Self::connected),
       process::defer(self(), &Self::disconnected),
-      process::defer(self(), &Self::received, lambda::_1)));
+      process::defer(self(), &Self::received, lambda::_1),
+      None()));
   }
 
   void connected()

http://git-wip-us.apache.org/repos/asf/mesos/blob/6348b5e4/src/examples/test_http_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_http_framework.cpp b/src/examples/test_http_framework.cpp
index cba520e..8cc3107 100644
--- a/src/examples/test_http_framework.cpp
+++ b/src/examples/test_http_framework.cpp
@@ -199,7 +199,8 @@ virtual void initialize()
       mesos::ContentType::PROTOBUF,
       process::defer(self(), &Self::connected),
       process::defer(self(), &Self::disconnected),
-      process::defer(self(), &Self::received, lambda::_1)));
+      process::defer(self(), &Self::received, lambda::_1),
+      None()));
 }
 
 private:


[3/9] mesos git commit: Fixed per framework principal metrics for HTTP frameworks.

Posted by vi...@apache.org.
Fixed per framework principal metrics for HTTP frameworks.

Use the `principal` set in `FrameworkInfo.principal` to populate
framework metrics instead of looking them up in `authenticated`
map. It also ensures that HTTP->PID framework downgrades preserve
the metrics and no additional logic is needed to deal with this.
(Previously HTTP frameworks never had AuthN and no principal was
passed in \`FrameworkInfo\`, so this was never a concern).

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


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

Branch: refs/heads/master
Commit: 82e43641dca28dc328a3b441275988e148e60f74
Parents: 81793f4
Author: Anand Mazumdar <ma...@gmail.com>
Authored: Fri Apr 15 15:59:11 2016 -0500
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 15 15:59:11 2016 -0500

----------------------------------------------------------------------
 src/master/master.cpp | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/82e43641/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 963cc29..37f4648 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -5940,30 +5940,25 @@ void Master::addFramework(Framework* framework)
       framework->info,
       framework->usedResources);
 
-  // Export framework metrics.
+  // Export framework metrics if a principal is specified in `FrameworkInfo`.
 
-  // If the framework is authenticated, its principal should be in
-  // 'authenticated'. Otherwise look if it's supplied in
-  // FrameworkInfo.
-  if (framework->pid.isSome()) {
-    Option<string> principal = authenticated.get(framework->pid.get());
-    if (principal.isNone() && framework->info.has_principal()) {
-      principal = framework->info.principal();
-    }
+  Option<string> principal = framework->info.has_principal()
+      ? Option<string>(framework->info.principal())
+      : None();
 
+  if (framework->pid.isSome()) {
     CHECK(!frameworks.principals.contains(framework->pid.get()));
     frameworks.principals.put(framework->pid.get(), principal);
+  }
 
-    // Export framework metrics if a principal is specified.
-    if (principal.isSome()) {
-      // Create new framework metrics if this framework is the first
-      // one of this principal. Otherwise existing metrics are reused.
-      if (!metrics->frameworks.contains(principal.get())) {
-        metrics->frameworks.put(
-            principal.get(),
-            Owned<Metrics::Frameworks>(
-              new Metrics::Frameworks(principal.get())));
-      }
+  if (principal.isSome()) {
+    // Create new framework metrics if this framework is the first
+    // one of this principal. Otherwise existing metrics are reused.
+    if (!metrics->frameworks.contains(principal.get())) {
+      metrics->frameworks.put(
+          principal.get(),
+          Owned<Metrics::Frameworks>(
+            new Metrics::Frameworks(principal.get())));
     }
   }
 }


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

Posted by vi...@apache.org.
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 {