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 2017/03/06 20:40:46 UTC

[10/14] mesos git commit: Updated master handlers to use the 'Principal' type.

Updated master handlers to use the 'Principal' type.

This patch updates the HTTP endpoint handlers in the
master process to accept the `Principal` type instead
of an `Option<string>& principal`.

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


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

Branch: refs/heads/master
Commit: da47646e22d5294ce48de57424bfa9b6562a6896
Parents: 8da4d6f
Author: Greg Mann <gr...@mesosphere.io>
Authored: Mon Mar 6 12:39:45 2017 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Mon Mar 6 12:39:45 2017 -0800

----------------------------------------------------------------------
 src/master/http.cpp            | 363 ++++++++++++++++++++++++------------
 src/master/master.cpp          | 155 +++++++--------
 src/master/master.hpp          | 192 +++++++++++--------
 src/master/quota_handler.cpp   |  56 +++---
 src/master/registrar.cpp       |   6 +-
 src/master/weights_handler.cpp |  34 ++--
 6 files changed, 497 insertions(+), 309 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/da47646e/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index b0b73e3..713ee0f 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -112,6 +112,8 @@ using process::http::TemporaryRedirect;
 using process::http::UnsupportedMediaType;
 using process::http::URL;
 
+using process::http::authentication::Principal;
+
 using std::copy_if;
 using std::list;
 using std::map;
@@ -124,6 +126,8 @@ using std::vector;
 
 namespace mesos {
 
+using mesos::authorization::createSubject;
+
 static void json(
     JSON::StringWriter* writer,
     const FrameworkInfo::Capability& capability)
@@ -469,8 +473,17 @@ string Master::Http::API_HELP()
 
 Future<Response> Master::Http::api(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // TODO(vinod): Add metrics for rejected requests.
 
   // TODO(vinod): Add support for rate limiting.
@@ -652,7 +665,7 @@ Future<Response> Master::Http::api(
 
 Future<Response> Master::Http::subscribe(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::SUBSCRIBE, call.type());
@@ -662,11 +675,7 @@ Future<Response> Master::Http::subscribe(
   Future<Owned<ObjectApprover>> tasksApprover;
   Future<Owned<ObjectApprover>> executorsApprover;
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -741,8 +750,17 @@ string Master::Http::SCHEDULER_HELP()
 
 Future<Response> Master::Http::scheduler(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // TODO(vinod): Add metrics for rejected requests.
 
   // TODO(vinod): Add support for rate limiting.
@@ -833,20 +851,24 @@ Future<Response> Master::Http::scheduler(
 
     const FrameworkInfo& frameworkInfo = call.subscribe().framework_info();
 
+    // We allow an authenticated framework to not specify a principal in
+    // `FrameworkInfo`, but in that case we log a WARNING here. We also set
+    // `FrameworkInfo.principal` to the value of the authenticated principal
+    // and use it for authorization later.
+    //
+    // NOTE: Common validation code, called previously, verifies that the
+    // authenticated principal is the same as `FrameworkInfo.principal`,
+    // if present.
     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());
-      }
+      CHECK_SOME(principal->value);
+
+      LOG(WARNING)
+        << "Setting 'principal' in FrameworkInfo to '" << principal->value.get()
+        << "' because the framework authenticated with that principal but "
+        << "did not set it in FrameworkInfo";
+
+      call.mutable_subscribe()->mutable_framework_info()->set_principal(
+          principal->value.get());
     }
 
     Pipe pipe;
@@ -876,7 +898,7 @@ Future<Response> Master::Http::scheduler(
 
   if (principal.isSome() && principal != framework->info.principal()) {
     return BadRequest(
-        "Authenticated principal '" + principal.get() + "' does not "
+        "Authenticated principal '" + stringify(principal.get()) + "' does not "
         "match principal '" + framework->info.principal() + "' set in "
         "`FrameworkInfo`");
   }
@@ -1012,8 +1034,17 @@ string Master::Http::CREATE_VOLUMES_HELP()
 
 Future<Response> Master::Http::createVolumes(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -1083,7 +1114,7 @@ Future<Response> Master::Http::createVolumes(
 Future<Response> Master::Http::_createVolumes(
     const SlaveID& slaveId,
     const RepeatedPtrField<Resource>& volumes,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   Slave* slave = master->slaves.registered.get(slaveId);
   if (slave == nullptr) {
@@ -1118,9 +1149,18 @@ Future<Response> Master::Http::_createVolumes(
 
 Future<Response> Master::Http::createVolumes(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   CHECK_EQ(mesos::master::Call::CREATE_VOLUMES, call.type());
   CHECK(call.has_create_volumes());
 
@@ -1161,8 +1201,17 @@ string Master::Http::DESTROY_VOLUMES_HELP()
 
 Future<Response> Master::Http::destroyVolumes(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -1232,7 +1281,7 @@ Future<Response> Master::Http::destroyVolumes(
 Future<Response> Master::Http::_destroyVolumes(
     const SlaveID& slaveId,
     const RepeatedPtrField<Resource>& volumes,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   Slave* slave = master->slaves.registered.get(slaveId);
   if (slave == nullptr) {
@@ -1267,9 +1316,18 @@ Future<Response> Master::Http::_destroyVolumes(
 
 Future<Response> Master::Http::destroyVolumes(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   CHECK_EQ(mesos::master::Call::DESTROY_VOLUMES, call.type());
   CHECK(call.has_destroy_volumes());
 
@@ -1299,8 +1357,17 @@ string Master::Http::FRAMEWORKS_HELP()
 
 Future<Response> Master::Http::frameworks(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -1313,11 +1380,7 @@ Future<Response> Master::Http::frameworks(
   Future<Owned<ObjectApprover>> executorsApprover;
 
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -1469,7 +1532,7 @@ mesos::master::Response::GetFrameworks::Framework model(
 
 Future<Response> Master::Http::getFrameworks(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_FRAMEWORKS, call.type());
@@ -1478,15 +1541,10 @@ Future<Response> Master::Http::getFrameworks(
   Future<Owned<ObjectApprover>> frameworksApprover;
 
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
-
   } else {
     frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
   }
@@ -1536,7 +1594,7 @@ mesos::master::Response::GetFrameworks Master::Http::_getFrameworks(
 
 Future<Response> Master::Http::getExecutors(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_EXECUTORS, call.type());
@@ -1545,11 +1603,7 @@ Future<Response> Master::Http::getExecutors(
   Future<Owned<ObjectApprover>> frameworksApprover;
   Future<Owned<ObjectApprover>> executorsApprover;
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -1667,7 +1721,7 @@ mesos::master::Response::GetExecutors Master::Http::_getExecutors(
 
 Future<Response> Master::Http::getState(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_STATE, call.type());
@@ -1677,11 +1731,7 @@ Future<Response> Master::Http::getState(
   Future<Owned<ObjectApprover>> tasksApprover;
   Future<Owned<ObjectApprover>> executorsApprover;
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -1784,8 +1834,17 @@ string Master::Http::FLAGS_HELP()
 
 Future<Response> Master::Http::flags(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // TODO(nfnt): Remove check for enabled
   // authorization as part of MESOS-5346.
   if (request.method != "GET" && master->authorizer.isSome()) {
@@ -1812,7 +1871,7 @@ Future<Response> Master::Http::flags(
 
 
 Future<Try<JSON::Object, Master::Http::FlagsError>> Master::Http::_flags(
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   if (master->authorizer.isNone()) {
     return __flags();
@@ -1821,8 +1880,9 @@ Future<Try<JSON::Object, Master::Http::FlagsError>> Master::Http::_flags(
   authorization::Request authRequest;
   authRequest.set_action(authorization::VIEW_FLAGS);
 
-  if (principal.isSome()) {
-    authRequest.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    authRequest.mutable_subject()->CopyFrom(subject.get());
   }
 
   return master->authorizer.get()->authorized(authRequest)
@@ -1859,7 +1919,7 @@ JSON::Object Master::Http::__flags() const
 
 Future<Response> Master::Http::getFlags(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_FLAGS, call.type());
@@ -1904,7 +1964,7 @@ Future<Response> Master::Http::health(const Request& request) const
 
 Future<Response> Master::Http::getHealth(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_HEALTH, call.type());
@@ -1920,7 +1980,7 @@ Future<Response> Master::Http::getHealth(
 
 Future<Response> Master::Http::getVersion(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_VERSION, call.type());
@@ -1933,7 +1993,7 @@ Future<Response> Master::Http::getVersion(
 
 Future<Response> Master::Http::getMetrics(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_METRICS, call.type());
@@ -1965,7 +2025,7 @@ Future<Response> Master::Http::getMetrics(
 
 Future<Response> Master::Http::getLoggingLevel(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_LOGGING_LEVEL, call.type());
@@ -1981,7 +2041,7 @@ Future<Response> Master::Http::getLoggingLevel(
 
 Future<Response> Master::Http::setLoggingLevel(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
   CHECK_EQ(mesos::master::Call::SET_LOGGING_LEVEL, call.type());
@@ -2000,7 +2060,7 @@ Future<Response> Master::Http::setLoggingLevel(
 
 Future<Response> Master::Http::getMaster(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_MASTER, call.type());
@@ -2125,8 +2185,17 @@ string Master::Http::RESERVE_HELP()
 
 Future<Response> Master::Http::reserve(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -2197,7 +2266,7 @@ Future<Response> Master::Http::reserve(
 Future<Response> Master::Http::_reserve(
     const SlaveID& slaveId,
     const Resources& resources,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   Slave* slave = master->slaves.registered.get(slaveId);
   if (slave == nullptr) {
@@ -2233,7 +2302,7 @@ Future<Response> Master::Http::_reserve(
 
 Future<Response> Master::Http::reserveResources(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::RESERVE_RESOURCES, call.type());
@@ -2265,7 +2334,7 @@ string Master::Http::SLAVES_HELP()
 
 Future<Response> Master::Http::slaves(
     const Request& request,
-    const Option<string>& /*principal*/) const
+    const Option<Principal>&) const
 {
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
@@ -2341,7 +2410,7 @@ Future<Response> Master::Http::slaves(
 
 Future<process::http::Response> Master::Http::getAgents(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_AGENTS, call.type());
@@ -2404,8 +2473,17 @@ string Master::Http::QUOTA_HELP()
 
 Future<Response> Master::Http::quota(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -2455,8 +2533,17 @@ string Master::Http::WEIGHTS_HELP()
 
 Future<Response> Master::Http::weights(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -2571,8 +2658,17 @@ string Master::Http::STATE_HELP()
 
 Future<Response> Master::Http::state(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -2585,11 +2681,7 @@ Future<Response> Master::Http::state(
   Future<Owned<ObjectApprover>> flagsApprover;
 
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -2815,7 +2907,7 @@ Future<Response> Master::Http::state(
 
 Future<Response> Master::Http::readFile(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::READ_FILE, call.type());
@@ -3065,8 +3157,17 @@ string Master::Http::STATESUMMARY_HELP()
 
 Future<Response> Master::Http::stateSummary(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -3075,11 +3176,7 @@ Future<Response> Master::Http::stateSummary(
   Future<Owned<ObjectApprover>> frameworksApprover;
 
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -3279,21 +3376,16 @@ string Master::Http::ROLES_HELP()
 
 
 Future<vector<string>> Master::Http::_roles(
-        const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   // Retrieve `ObjectApprover`s for authorizing roles.
   Future<Owned<ObjectApprover>> rolesApprover;
 
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     rolesApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_ROLE);
-
   } else {
     rolesApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
   }
@@ -3346,8 +3438,17 @@ Future<vector<string>> Master::Http::_roles(
 
 Future<Response> Master::Http::roles(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -3386,7 +3487,7 @@ Future<Response> Master::Http::roles(
 
 Future<Response> Master::Http::listFiles(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::LIST_FILES, call.type());
@@ -3438,7 +3539,7 @@ Future<Response> Master::Http::listFiles(
 // convert back into a `Resource` object.
 Future<Response> Master::Http::getRoles(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_ROLES, call.type());
@@ -3508,8 +3609,17 @@ string Master::Http::TEARDOWN_HELP()
 
 Future<Response> Master::Http::teardown(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -3553,8 +3663,9 @@ Future<Response> Master::Http::teardown(
   authorization::Request teardown;
   teardown.set_action(authorization::TEARDOWN_FRAMEWORK);
 
-  if (principal.isSome()) {
-    teardown.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    teardown.mutable_subject()->CopyFrom(subject.get());
   }
 
   if (framework->info.has_principal()) {
@@ -3666,8 +3777,17 @@ string Master::Http::TASKS_HELP()
 
 Future<Response> Master::Http::tasks(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -3687,11 +3807,7 @@ Future<Response> Master::Http::tasks(
   Future<Owned<ObjectApprover>> frameworksApprover;
   Future<Owned<ObjectApprover>> tasksApprover;
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -3793,7 +3909,7 @@ Future<Response> Master::Http::tasks(
 
 Future<Response> Master::Http::getTasks(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_TASKS, call.type());
@@ -3802,11 +3918,7 @@ Future<Response> Master::Http::getTasks(
   Future<Owned<ObjectApprover>> frameworksApprover;
   Future<Owned<ObjectApprover>> tasksApprover;
   if (master->authorizer.isSome()) {
-    Option<authorization::Subject> subject;
-    if (principal.isSome()) {
-      subject = authorization::Subject();
-      subject->set_value(principal.get());
-    }
+    Option<authorization::Subject> subject = createSubject(principal);
 
     frameworksApprover = master->authorizer.get()->getObjectApprover(
         subject, authorization::VIEW_FRAMEWORK);
@@ -3969,7 +4081,7 @@ string Master::Http::MAINTENANCE_SCHEDULE_HELP()
 // /master/maintenance/schedule endpoint handler.
 Future<Response> Master::Http::maintenanceSchedule(
     const Request& request,
-    const Option<string>& /*principal*/) const
+    const Option<Principal>&) const
 {
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
@@ -4108,7 +4220,7 @@ Future<Response> Master::Http::_updateMaintenanceSchedule(
 
 Future<Response> Master::Http::getMaintenanceSchedule(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_MAINTENANCE_SCHEDULE, call.type());
@@ -4125,7 +4237,7 @@ Future<Response> Master::Http::getMaintenanceSchedule(
 
 Future<Response> Master::Http::updateMaintenanceSchedule(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
   CHECK_EQ(mesos::master::Call::UPDATE_MAINTENANCE_SCHEDULE, call.type());
@@ -4160,7 +4272,7 @@ string Master::Http::MACHINE_DOWN_HELP()
 // /master/machine/down endpoint handler.
 Future<Response> Master::Http::machineDown(
     const Request& request,
-    const Option<string>& /*principal*/) const
+    const Option<Principal>&) const
 {
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
@@ -4262,7 +4374,7 @@ Future<Response> Master::Http::_startMaintenance(
 
 Future<Response> Master::Http::startMaintenance(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
   CHECK_EQ(mesos::master::Call::START_MAINTENANCE, call.type());
@@ -4296,7 +4408,7 @@ string Master::Http::MACHINE_UP_HELP()
 // /master/machine/up endpoint handler.
 Future<Response> Master::Http::machineUp(
     const Request& request,
-    const Option<string>& /*principal*/) const
+    const Option<Principal>&) const
 {
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
@@ -4397,7 +4509,7 @@ Future<Response> Master::Http::_stopMaintenance(
 
 Future<Response> Master::Http::stopMaintenance(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType /*contentType*/) const
 {
   CHECK_EQ(mesos::master::Call::STOP_MAINTENANCE, call.type());
@@ -4434,7 +4546,7 @@ string Master::Http::MAINTENANCE_STATUS_HELP()
 // /master/maintenance/status endpoint handler.
 Future<Response> Master::Http::maintenanceStatus(
     const Request& request,
-    const Option<string>& /*principal*/) const
+    const Option<Principal>&) const
 {
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
@@ -4511,7 +4623,7 @@ Future<mesos::maintenance::ClusterStatus>
 
 Future<Response> Master::Http::getMaintenanceStatus(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_MAINTENANCE_STATUS, call.type());
@@ -4560,8 +4672,17 @@ string Master::Http::UNRESERVE_HELP()
 
 Future<Response> Master::Http::unreserve(
     const Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
   // When current master is not the leader, redirect to the leading master.
   if (!master->elected()) {
     return redirect(request);
@@ -4632,7 +4753,7 @@ Future<Response> Master::Http::unreserve(
 Future<Response> Master::Http::_unreserve(
     const SlaveID& slaveId,
     const Resources& resources,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   Slave* slave = master->slaves.registered.get(slaveId);
   if (slave == nullptr) {
@@ -4724,7 +4845,7 @@ Future<Response> Master::Http::_operation(
 
 Future<Response> Master::Http::unreserveResources(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::UNRESERVE_RESOURCES, call.type());

http://git-wip-us.apache.org/repos/asf/mesos/blob/da47646e/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index a15c6d8..3fa5438 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -118,6 +118,8 @@ using process::UPID;
 
 using process::http::Pipe;
 
+using process::http::authentication::Principal;
+
 using process::metrics::Counter;
 
 namespace mesos {
@@ -126,6 +128,8 @@ namespace master {
 
 using mesos::allocator::Allocator;
 
+using mesos::authorization::createSubject;
+
 using mesos::master::contender::MasterContender;
 
 using mesos::master::detector::MasterDetector;
@@ -856,7 +860,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::API_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.api(request, principal);
         });
@@ -864,7 +868,7 @@ void Master::initialize()
         DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM,
         Http::SCHEDULER_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.scheduler(request, principal);
         });
@@ -872,7 +876,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::CREATE_VOLUMES_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.createVolumes(request, principal);
         });
@@ -880,7 +884,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::DESTROY_VOLUMES_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.destroyVolumes(request, principal);
         });
@@ -888,7 +892,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::FRAMEWORKS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.frameworks(request, principal);
         });
@@ -896,7 +900,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::FLAGS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.flags(request, principal);
         });
@@ -914,7 +918,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::RESERVE_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.reserve(request, principal);
         });
@@ -924,7 +928,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::ROLES_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.roles(request, principal);
         });
@@ -932,7 +936,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::ROLES_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.roles(request, principal);
         });
@@ -940,7 +944,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::TEARDOWN_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.teardown(request, principal);
         });
@@ -948,7 +952,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::SLAVES_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.slaves(request, principal);
         });
@@ -958,7 +962,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::STATE_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.state(request, principal);
         });
@@ -966,7 +970,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::STATE_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.state(request, principal);
         });
@@ -974,7 +978,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::STATESUMMARY_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.stateSummary(request, principal);
         });
@@ -984,7 +988,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::TASKS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.tasks(request, principal);
         });
@@ -992,7 +996,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::TASKS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.tasks(request, principal);
         });
@@ -1000,7 +1004,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::MAINTENANCE_SCHEDULE_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.maintenanceSchedule(request, principal);
         });
@@ -1008,7 +1012,7 @@ void Master::initialize()
         READONLY_HTTP_AUTHENTICATION_REALM,
         Http::MAINTENANCE_STATUS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.maintenanceStatus(request, principal);
         });
@@ -1016,7 +1020,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::MACHINE_DOWN_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.machineDown(request, principal);
         });
@@ -1024,7 +1028,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::MACHINE_UP_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.machineUp(request, principal);
         });
@@ -1032,7 +1036,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::UNRESERVE_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.unreserve(request, principal);
         });
@@ -1040,7 +1044,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::QUOTA_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.quota(request, principal);
         });
@@ -1048,7 +1052,7 @@ void Master::initialize()
         READWRITE_HTTP_AUTHENTICATION_REALM,
         Http::WEIGHTS_HELP(),
         [this](const process::http::Request& request,
-               const Option<string>& principal) {
+               const Option<Principal>& principal) {
           Http::log(request);
           return http.weights(request, principal);
         });
@@ -1063,7 +1067,7 @@ void Master::initialize()
 
   const PID<Master> masterPid = self();
 
-  auto authorize = [masterPid](const Option<string>& principal) {
+  auto authorize = [masterPid](const Option<Principal>& principal) {
     return dispatch(masterPid, &Master::authorizeLogAccess, principal);
   };
 
@@ -1405,7 +1409,7 @@ void Master::_exited(Framework* framework)
 }
 
 
-Future<bool> Master::authorizeLogAccess(const Option<string>& principal)
+Future<bool> Master::authorizeLogAccess(const Option<Principal>& principal)
 {
   if (authorizer.isNone()) {
     return true;
@@ -1414,8 +1418,9 @@ Future<bool> Master::authorizeLogAccess(const Option<string>& principal)
   authorization::Request request;
   request.set_action(authorization::ACCESS_MESOS_LOG);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   return authorizer.get()->authorized(request);
@@ -1558,6 +1563,8 @@ void Master::visit(const ExitedEvent& event)
 }
 
 
+// TODO(greggomann): Change this to accept an `Option<Principal>`
+// when MESOS-7202 is resolved.
 void Master::throttled(
     const MessageEvent& event,
     const Option<string>& principal)
@@ -1600,6 +1607,8 @@ void Master::_visit(const MessageEvent& event)
 }
 
 
+// TODO(greggomann): Change this to accept an `Option<Principal>`
+// when MESOS-7202 is resolved.
 void Master::exceededCapacity(
     const MessageEvent& event,
     const Option<string>& principal,
@@ -3411,7 +3420,7 @@ Future<bool> Master::authorizeTask(
 
 Future<bool> Master::authorizeReserveResources(
     const Offer::Operation::Reserve& reserve,
-    const Option<string>& principal)
+    const Option<Principal>& principal)
 {
   if (authorizer.isNone()) {
     return true; // Authorization is disabled.
@@ -3420,11 +3429,12 @@ Future<bool> Master::authorizeReserveResources(
   authorization::Request request;
   request.set_action(authorization::RESERVE_RESOURCES);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
-  // The operation will be authorized if the principal is allowed to make
+  // The operation will be authorized if the entity is allowed to make
   // reservations for all roles included in `reserve.resources`.
   // Add an element to `request.roles` for each unique role in the resources.
   hashset<string> roles;
@@ -3440,7 +3450,7 @@ Future<bool> Master::authorizeReserveResources(
   }
 
   LOG(INFO) << "Authorizing principal '"
-            << (principal.isSome() ? principal.get() : "ANY")
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
             << "' to reserve resources '" << reserve.resources() << "'";
 
   // NOTE: Empty authorizations are not valid and are checked by a validator.
@@ -3468,7 +3478,7 @@ Future<bool> Master::authorizeReserveResources(
 
 Future<bool> Master::authorizeUnreserveResources(
     const Offer::Operation::Unreserve& unreserve,
-    const Option<string>& principal)
+    const Option<Principal>& principal)
 {
   if (authorizer.isNone()) {
     return true; // Authorization is disabled.
@@ -3477,8 +3487,9 @@ Future<bool> Master::authorizeUnreserveResources(
   authorization::Request request;
   request.set_action(authorization::UNRESERVE_RESOURCES);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   list<Future<bool>> authorizations;
@@ -3498,10 +3509,9 @@ Future<bool> Master::authorizeUnreserveResources(
     }
   }
 
-  LOG(INFO)
-    << "Authorizing principal '"
-    << (principal.isSome() ? principal.get() : "ANY")
-    << "' to unreserve resources '" << unreserve.resources() << "'";
+  LOG(INFO) << "Authorizing principal '"
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
+            << "' to unreserve resources '" << unreserve.resources() << "'";
 
   if (authorizations.empty()) {
     return authorizer.get()->authorized(request);
@@ -3523,7 +3533,7 @@ Future<bool> Master::authorizeUnreserveResources(
 
 Future<bool> Master::authorizeCreateVolume(
     const Offer::Operation::Create& create,
-    const Option<string>& principal)
+    const Option<Principal>& principal)
 {
   if (authorizer.isNone()) {
     return true; // Authorization is disabled.
@@ -3532,11 +3542,12 @@ Future<bool> Master::authorizeCreateVolume(
   authorization::Request request;
   request.set_action(authorization::CREATE_VOLUME);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
-  // The operation will be authorized if the principal is allowed to create
+  // The operation will be authorized if the entity is allowed to create
   // volumes for all roles included in `create.volumes`.
   // Add an element to `request.roles` for each unique role in the volumes.
   hashset<string> roles;
@@ -3551,10 +3562,9 @@ Future<bool> Master::authorizeCreateVolume(
     }
   }
 
-  LOG(INFO)
-    << "Authorizing principal '"
-    << (principal.isSome() ? principal.get() : "ANY")
-    << "' to create volumes";
+  LOG(INFO) << "Authorizing principal '"
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
+            << "' to create volumes '" << create.volumes() << "'";
 
   if (authorizations.empty()) {
     return authorizer.get()->authorized(request);
@@ -3576,7 +3586,7 @@ Future<bool> Master::authorizeCreateVolume(
 
 Future<bool> Master::authorizeDestroyVolume(
     const Offer::Operation::Destroy& destroy,
-    const Option<string>& principal)
+    const Option<Principal>& principal)
 {
   if (authorizer.isNone()) {
     return true; // Authorization is disabled.
@@ -3585,8 +3595,9 @@ Future<bool> Master::authorizeDestroyVolume(
   authorization::Request request;
   request.set_action(authorization::DESTROY_VOLUME);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   list<Future<bool>> authorizations;
@@ -3603,11 +3614,9 @@ Future<bool> Master::authorizeDestroyVolume(
     }
   }
 
-  LOG(INFO)
-    << "Authorizing principal '"
-    << (principal.isSome() ? principal.get() : "ANY")
-    << "' to destroy volumes '"
-    << stringify(destroy.volumes()) << "'";
+  LOG(INFO) << "Authorizing principal '"
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
+            << "' to destroy volumes '" << destroy.volumes() << "'";
 
   if (authorizations.empty()) {
     return authorizer.get()->authorized(request);
@@ -3876,9 +3885,9 @@ void Master::accept(
 
       // The RESERVE operation allows a principal to reserve resources.
       case Offer::Operation::RESERVE: {
-        Option<string> principal = framework->info.has_principal()
-          ? framework->info.principal()
-          : Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         futures.push_back(
             authorizeReserveResources(
@@ -3889,9 +3898,9 @@ void Master::accept(
 
       // The UNRESERVE operation allows a principal to unreserve resources.
       case Offer::Operation::UNRESERVE: {
-        Option<string> principal = framework->info.has_principal()
-          ? framework->info.principal()
-          : Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         futures.push_back(
             authorizeUnreserveResources(
@@ -3902,9 +3911,9 @@ void Master::accept(
 
       // The CREATE operation allows the creation of a persistent volume.
       case Offer::Operation::CREATE: {
-        Option<string> principal = framework->info.has_principal()
-          ? framework->info.principal()
-          : Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         futures.push_back(
             authorizeCreateVolume(
@@ -3915,9 +3924,9 @@ void Master::accept(
 
       // The DESTROY operation allows the destruction of a persistent volume.
       case Offer::Operation::DESTROY: {
-        Option<string> principal = framework->info.has_principal()
-          ? framework->info.principal()
-          : Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         futures.push_back(
             authorizeDestroyVolume(
@@ -4100,9 +4109,9 @@ void Master::_accept(
           continue;
         }
 
-        Option<string> principal = framework->info.has_principal()
-          ? framework->info.principal()
-          : Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         // Make sure this reserve operation is valid.
         Option<Error> error = validation::operation::validate(
@@ -4213,9 +4222,9 @@ void Master::_accept(
           continue;
         }
 
-        Option<string> principal = framework->info.has_principal() ?
-          framework->info.principal() :
-          Option<string>::none();
+        Option<Principal> principal = framework->info.has_principal()
+          ? Principal(framework->info.principal())
+          : Option<Principal>::none();
 
         // Make sure this create operation is valid.
         Option<Error> error = validation::operation::validate(

http://git-wip-us.apache.org/repos/asf/mesos/blob/da47646e/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 81320e0..47c5e61 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -680,7 +680,7 @@ protected:
    */
   process::Future<bool> authorizeReserveResources(
       const Offer::Operation::Reserve& reserve,
-      const Option<std::string>& principal);
+      const Option<process::http::authentication::Principal>& principal);
 
   /**
    * Authorizes an `UNRESERVE` offer operation.
@@ -701,7 +701,7 @@ protected:
    */
   process::Future<bool> authorizeUnreserveResources(
       const Offer::Operation::Unreserve& unreserve,
-      const Option<std::string>& principal);
+      const Option<process::http::authentication::Principal>& principal);
 
   /**
    * Authorizes a `CREATE` offer operation.
@@ -722,7 +722,7 @@ protected:
    */
   process::Future<bool> authorizeCreateVolume(
       const Offer::Operation::Create& create,
-      const Option<std::string>& principal);
+      const Option<process::http::authentication::Principal>& principal);
 
   /**
    * Authorizes a `DESTROY` offer operation.
@@ -743,7 +743,7 @@ protected:
    */
   process::Future<bool> authorizeDestroyVolume(
       const Offer::Operation::Destroy& destroy,
-      const Option<std::string>& principal);
+      const Option<process::http::authentication::Principal>& principal);
 
   // Add the task and its executor (if not already running) to the
   // framework and slave. Returns the resources consumed as a result,
@@ -931,7 +931,7 @@ private:
       const process::Future<bool>& registrarResult);
 
   process::Future<bool> authorizeLogAccess(
-      const Option<std::string>& principal);
+      const Option<process::http::authentication::Principal>& principal);
 
   /**
    * Returns whether the given role is on the whitelist.
@@ -976,28 +976,33 @@ private:
     // Returns a list of set quotas.
     process::Future<process::http::Response> status(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> status(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> set(
         const mesos::master::Call& call,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> set(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> remove(
         const mesos::master::Call& call,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> remove(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
   private:
     // Heuristically tries to determine whether a quota request could
@@ -1045,7 +1050,7 @@ private:
     void rescindOffers(const mesos::quota::QuotaInfo& request) const;
 
     process::Future<bool> authorizeGetQuota(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const mesos::quota::QuotaInfo& quotaInfo) const;
 
     // TODO(mpark): The following functions `authorizeSetQuota` and
@@ -1053,19 +1058,21 @@ private:
     // the end of deprecation cycle which started with 1.0.
 
     process::Future<bool> authorizeSetQuota(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const mesos::quota::QuotaInfo& quotaInfo) const;
 
     process::Future<bool> authorizeRemoveQuota(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const mesos::quota::QuotaInfo& quotaInfo) const;
 
     process::Future<mesos::quota::QuotaStatus> _status(
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> _set(
         const mesos::quota::QuotaRequest& quotaRequest,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> __set(
         const mesos::quota::QuotaInfo& quotaInfo,
@@ -1073,7 +1080,8 @@ private:
 
     process::Future<process::http::Response> _remove(
         const std::string& role,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> __remove(
         const std::string& role) const;
@@ -1101,29 +1109,31 @@ private:
 
     process::Future<process::http::Response> get(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> get(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> update(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> update(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
   private:
     process::Future<bool> authorizeGetWeight(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const WeightInfo& weight) const;
 
     process::Future<bool> authorizeUpdateWeights(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const std::vector<std::string>& roles) const;
 
     process::Future<std::vector<WeightInfo>> _filterWeights(
@@ -1131,10 +1141,11 @@ private:
         const std::list<bool>& roleAuthorizations) const;
 
     process::Future<std::vector<WeightInfo>> _getWeights(
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response>_updateWeights(
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         const google::protobuf::RepeatedPtrField<WeightInfo>& weightInfos)
             const;
 
@@ -1164,32 +1175,38 @@ private:
     // /api/v1
     process::Future<process::http::Response> api(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /api/v1/scheduler
     process::Future<process::http::Response> scheduler(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/create-volumes
     process::Future<process::http::Response> createVolumes(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/destroy-volumes
     process::Future<process::http::Response> destroyVolumes(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/flags
     process::Future<process::http::Response> flags(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/frameworks
     process::Future<process::http::Response> frameworks(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/health
     process::Future<process::http::Response> health(
@@ -1202,72 +1219,86 @@ private:
     // /master/reserve
     process::Future<process::http::Response> reserve(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/roles
     process::Future<process::http::Response> roles(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/teardown
     process::Future<process::http::Response> teardown(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/slaves
     process::Future<process::http::Response> slaves(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/state
     process::Future<process::http::Response> state(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/state-summary
     process::Future<process::http::Response> stateSummary(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/tasks
     process::Future<process::http::Response> tasks(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/maintenance/schedule
     process::Future<process::http::Response> maintenanceSchedule(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/maintenance/status
     process::Future<process::http::Response> maintenanceStatus(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/machine/down
     process::Future<process::http::Response> machineDown(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/machine/up
     process::Future<process::http::Response> machineUp(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/unreserve
     process::Future<process::http::Response> unreserve(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/quota
     process::Future<process::http::Response> quota(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // /master/weights
     process::Future<process::http::Response> weights(
         const process::http::Request& request,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     static std::string API_HELP();
     static std::string SCHEDULER_HELP();
@@ -1298,13 +1329,15 @@ private:
     class FlagsError; // Forward declaration.
 
     process::Future<Try<JSON::Object, FlagsError>> _flags(
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<std::vector<const Task*>> _tasks(
         const size_t limit,
         const size_t offset,
         const std::string& order,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> _teardown(
         const FrameworkID& id) const;
@@ -1326,22 +1359,26 @@ private:
     process::Future<process::http::Response> _reserve(
         const SlaveID& slaveId,
         const Resources& resources,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> _unreserve(
         const SlaveID& slaveId,
         const Resources& resources,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> _createVolumes(
         const SlaveID& slaveId,
         const google::protobuf::RepeatedPtrField<Resource>& volumes,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     process::Future<process::http::Response> _destroyVolumes(
         const SlaveID& slaveId,
         const google::protobuf::RepeatedPtrField<Resource>& volumes,
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     /**
      * Continuation for operations: /reserve, /unreserve,
@@ -1368,90 +1405,91 @@ private:
         const Offer::Operation& operation) const;
 
     process::Future<std::vector<std::string>> _roles(
-        const Option<std::string>& principal) const;
+        const Option<process::http::authentication::Principal>&
+            principal) const;
 
     // Master API handlers.
 
     process::Future<process::http::Response> getAgents(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     mesos::master::Response::GetAgents _getAgents() const;
 
     process::Future<process::http::Response> getFlags(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getHealth(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getVersion(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getRoles(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getMetrics(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getLoggingLevel(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> setLoggingLevel(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> listFiles(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getMaster(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> updateMaintenanceSchedule(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getMaintenanceSchedule(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getMaintenanceStatus(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> startMaintenance(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> stopMaintenance(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getTasks(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     mesos::master::Response::GetTasks _getTasks(
@@ -1460,27 +1498,27 @@ private:
 
     process::Future<process::http::Response> createVolumes(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> destroyVolumes(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> reserveResources(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> unreserveResources(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> getFrameworks(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     mesos::master::Response::GetFrameworks _getFrameworks(
@@ -1488,7 +1526,7 @@ private:
 
     process::Future<process::http::Response> getExecutors(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     mesos::master::Response::GetExecutors _getExecutors(
@@ -1497,7 +1535,7 @@ private:
 
     process::Future<process::http::Response> getState(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     mesos::master::Response::GetState _getState(
@@ -1507,12 +1545,12 @@ private:
 
     process::Future<process::http::Response> subscribe(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     process::Future<process::http::Response> readFile(
         const mesos::master::Call& call,
-        const Option<std::string>& principal,
+        const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
     Master* master;

http://git-wip-us.apache.org/repos/asf/mesos/blob/da47646e/src/master/quota_handler.cpp
----------------------------------------------------------------------
diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp
index 3ad28e4..5212ed7 100644
--- a/src/master/quota_handler.cpp
+++ b/src/master/quota_handler.cpp
@@ -50,6 +50,8 @@ using http::Conflict;
 using http::Forbidden;
 using http::OK;
 
+using mesos::authorization::createSubject;
+
 using mesos::quota::QuotaInfo;
 using mesos::quota::QuotaRequest;
 using mesos::quota::QuotaStatus;
@@ -57,6 +59,8 @@ using mesos::quota::QuotaStatus;
 using process::Future;
 using process::Owned;
 
+using process::http::authentication::Principal;
+
 using std::list;
 using std::string;
 using std::vector;
@@ -213,7 +217,7 @@ void Master::QuotaHandler::rescindOffers(const QuotaInfo& request) const
 
 Future<http::Response> Master::QuotaHandler::status(
     const mesos::master::Call& call,
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     ContentType contentType) const
 {
   CHECK_EQ(mesos::master::Call::GET_QUOTA, call.type());
@@ -232,7 +236,7 @@ Future<http::Response> Master::QuotaHandler::status(
 
 Future<http::Response> Master::QuotaHandler::status(
     const http::Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   VLOG(1) << "Handling quota status request";
 
@@ -247,7 +251,7 @@ Future<http::Response> Master::QuotaHandler::status(
 
 
 Future<QuotaStatus> Master::QuotaHandler::_status(
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   // Quotas can be updated during preparation of the response.
   // Copy current view of the collection to avoid conflicts.
@@ -296,7 +300,7 @@ Future<QuotaStatus> Master::QuotaHandler::_status(
 
 Future<http::Response> Master::QuotaHandler::set(
     const mesos::master::Call& call,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   CHECK_EQ(mesos::master::Call::SET_QUOTA, call.type());
   CHECK(call.has_set_quota());
@@ -307,7 +311,7 @@ Future<http::Response> Master::QuotaHandler::set(
 
 Future<http::Response> Master::QuotaHandler::set(
     const http::Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   VLOG(1) << "Setting quota from request: '" << request.body << "'";
 
@@ -338,7 +342,7 @@ Future<http::Response> Master::QuotaHandler::set(
 
 Future<http::Response> Master::QuotaHandler::_set(
     const QuotaRequest& quotaRequest,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   Try<QuotaInfo> create = quota::createQuotaInfo(quotaRequest);
   if (create.isError()) {
@@ -376,7 +380,12 @@ Future<http::Response> Master::QuotaHandler::_set(
   const bool forced = quotaRequest.force();
 
   if (principal.isSome()) {
-    quotaInfo.set_principal(principal.get());
+    // We assume that `principal->value.isSome()` is true. The master's HTTP
+    // handlers enforce this constraint, and V0 authenticators will only return
+    // principals of that form.
+    CHECK_SOME(principal->value);
+
+    quotaInfo.set_principal(principal->value.get());
   }
 
   return authorizeSetQuota(principal, quotaInfo)
@@ -439,7 +448,7 @@ Future<http::Response> Master::QuotaHandler::__set(
 
 Future<http::Response> Master::QuotaHandler::remove(
     const mesos::master::Call& call,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   CHECK_EQ(mesos::master::Call::REMOVE_QUOTA, call.type());
   CHECK(call.has_remove_quota());
@@ -450,7 +459,7 @@ Future<http::Response> Master::QuotaHandler::remove(
 
 Future<http::Response> Master::QuotaHandler::remove(
     const http::Request& request,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   VLOG(1) << "Removing quota for request path: '" << request.url.path << "'";
 
@@ -497,7 +506,7 @@ Future<http::Response> Master::QuotaHandler::remove(
 
 Future<http::Response> Master::QuotaHandler::_remove(
     const string& role,
-    const Option<string>& principal) const
+    const Option<Principal>& principal) const
 {
   return authorizeRemoveQuota(principal, master->quotas[role].info)
     .then(defer(master->self(), [=](bool authorized) -> Future<http::Response> {
@@ -531,7 +540,7 @@ Future<http::Response> Master::QuotaHandler::__remove(const string& role) const
 
 
 Future<bool> Master::QuotaHandler::authorizeGetQuota(
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     const QuotaInfo& quotaInfo) const
 {
   if (master->authorizer.isNone()) {
@@ -539,14 +548,15 @@ Future<bool> Master::QuotaHandler::authorizeGetQuota(
   }
 
   LOG(INFO) << "Authorizing principal '"
-            << (principal.isSome() ? principal.get() : "ANY")
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
             << "' to get quota for role '" << quotaInfo.role() << "'";
 
   authorization::Request request;
   request.set_action(authorization::GET_QUOTA);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   // TODO(alexr): The `value` field is set for backwards compatibility
@@ -561,7 +571,7 @@ Future<bool> Master::QuotaHandler::authorizeGetQuota(
 // TODO(zhitao): Remove this function at the end of the
 // deprecation cycle which started with 1.0.
 Future<bool> Master::QuotaHandler::authorizeSetQuota(
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     const QuotaInfo& quotaInfo) const
 {
   if (master->authorizer.isNone()) {
@@ -569,14 +579,15 @@ Future<bool> Master::QuotaHandler::authorizeSetQuota(
   }
 
   LOG(INFO) << "Authorizing principal '"
-            << (principal.isSome() ? principal.get() : "ANY")
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
             << "' to set quota for role '" << quotaInfo.role() << "'";
 
   authorization::Request request;
   request.set_action(authorization::UPDATE_QUOTA);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   request.mutable_object()->set_value("SetQuota");
@@ -589,7 +600,7 @@ Future<bool> Master::QuotaHandler::authorizeSetQuota(
 // TODO(zhitao): Remove this function at the end of the
 // deprecation cycle which started with 1.0.
 Future<bool> Master::QuotaHandler::authorizeRemoveQuota(
-    const Option<string>& principal,
+    const Option<Principal>& principal,
     const QuotaInfo& quotaInfo) const
 {
   if (master->authorizer.isNone()) {
@@ -597,14 +608,15 @@ Future<bool> Master::QuotaHandler::authorizeRemoveQuota(
   }
 
   LOG(INFO) << "Authorizing principal '"
-            << (principal.isSome() ? principal.get() : "ANY")
+            << (principal.isSome() ? stringify(principal.get()) : "ANY")
             << "' to remove quota for role '" << quotaInfo.role() << "'";
 
   authorization::Request request;
   request.set_action(authorization::UPDATE_QUOTA);
 
-  if (principal.isSome()) {
-    request.mutable_subject()->set_value(principal.get());
+  Option<authorization::Subject> subject = createSubject(principal);
+  if (subject.isSome()) {
+    request.mutable_subject()->CopyFrom(subject.get());
   }
 
   request.mutable_object()->set_value("RemoveQuota");

http://git-wip-us.apache.org/repos/asf/mesos/blob/da47646e/src/master/registrar.cpp
----------------------------------------------------------------------
diff --git a/src/master/registrar.cpp b/src/master/registrar.cpp
index d7134ee..0029cc7 100644
--- a/src/master/registrar.cpp
+++ b/src/master/registrar.cpp
@@ -65,6 +65,8 @@ using process::TLDR;
 
 using process::http::OK;
 
+using process::http::authentication::Principal;
+
 using process::metrics::Gauge;
 using process::metrics::Timer;
 
@@ -120,7 +122,7 @@ private:
   // /registrar(N)/registry
   Future<Response> registry(
       const Request& request,
-      const Option<string>& /* principal */);
+      const Option<Principal>&);
   static string registryHelp();
 
   // The 'Recover' operation adds the latest MasterInfo.
@@ -256,7 +258,7 @@ void fail(deque<Owned<Operation>>* operations, const string& message)
 
 Future<Response> RegistrarProcess::registry(
     const Request& request,
-    const Option<string>& /* principal */)
+    const Option<Principal>&)
 {
   JSON::Object result;