Updated common Mesos code to use the 'Principal' type. This patch updates common Mesos HTTP-related helpers, as well as the `authorization::Subject` protobuf message, to make use of the `Principal` type instead of an `Option<string> principal`.
Review: https://reviews.apache.org/r/56618/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1b4f33fa Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1b4f33fa Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1b4f33fa Branch: refs/heads/master Commit: 1b4f33fa2cdc0cfeab4cba1795e9d89e4bdae71e Parents: 66193c8 Author: Greg Mann <[email protected]> Authored: Mon Mar 6 12:39:04 2017 -0800 Committer: Vinod Kone <[email protected]> Committed: Mon Mar 6 12:39:04 2017 -0800 ---------------------------------------------------------------------- include/mesos/authorizer/authorizer.proto | 7 ++-- src/common/http.cpp | 49 +++++++++++++++++++++----- src/common/http.hpp | 11 +++++- 3 files changed, 55 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/1b4f33fa/include/mesos/authorizer/authorizer.proto ---------------------------------------------------------------------- diff --git a/include/mesos/authorizer/authorizer.proto b/include/mesos/authorizer/authorizer.proto index 9cc75b0..fdc4817 100644 --- a/include/mesos/authorizer/authorizer.proto +++ b/include/mesos/authorizer/authorizer.proto @@ -26,11 +26,14 @@ option java_outer_classname = "Protos"; // A `Subject` is the entity which desires to execute an `Action` on -// an `Object`. A `Subject` has a number of optional fields (currently -// only a `value`). +// an `Object`. A `Subject` has a number of optional fields: +// `value` : String which identifies the subject, i.e., a principal. +// `claims`: Key-value pairs associated with the subject. +// // NOTE: A `Subject` should always come with at least one set field. message Subject { optional string value = 1; + optional Labels claims = 2; } http://git-wip-us.apache.org/repos/asf/mesos/blob/1b4f33fa/src/common/http.cpp ---------------------------------------------------------------------- diff --git a/src/common/http.cpp b/src/common/http.cpp index 5d75ecd..0848f70 100644 --- a/src/common/http.cpp +++ b/src/common/http.cpp @@ -58,6 +58,8 @@ using process::Failure; using process::Owned; using process::http::authentication::Authenticator; +using process::http::authentication::Principal; + using process::http::authorization::AuthorizationCallbacks; using mesos::http::authentication::BasicAuthenticatorFactory; @@ -717,19 +719,44 @@ static void json(JSON::StringWriter* writer, const Value::Text& text) writer->append(text.value()); } +namespace authorization { + +const Option<authorization::Subject> createSubject( + const Option<Principal>& principal) +{ + if (principal.isSome()) { + authorization::Subject subject; + + if (principal->value.isSome()) { + subject.set_value(principal->value.get()); + } + + foreachpair (const string& key, const string& value, principal->claims) { + Label* claim = subject.mutable_claims()->mutable_labels()->Add(); + claim->set_key(key); + claim->set_value(value); + } + + return subject; + } + + return None(); +} + +} // namespace authorization { const AuthorizationCallbacks createAuthorizationCallbacks( Authorizer* authorizer) { typedef lambda::function<process::Future<bool>( const process::http::Request& httpRequest, - const Option<string>& principal)> Callback; + const Option<Principal>& principal)> Callback; AuthorizationCallbacks callbacks; Callback getEndpoint = [authorizer]( const process::http::Request& httpRequest, - const Option<string>& principal) -> process::Future<bool> { + const Option<Principal>& principal) -> process::Future<bool> { const string path = httpRequest.url.path; if (!internal::AUTHORIZABLE_ENDPOINTS.contains(path)) { @@ -740,14 +767,16 @@ const AuthorizationCallbacks createAuthorizationCallbacks( authorization::Request authRequest; authRequest.set_action(mesos::authorization::GET_ENDPOINT_WITH_PATH); - if (principal.isSome()) { - authRequest.mutable_subject()->set_value(principal.get()); + Option<authorization::Subject> subject = + authorization::createSubject(principal); + if (subject.isSome()) { + authRequest.mutable_subject()->CopyFrom(subject.get()); } authRequest.mutable_object()->set_value(path); LOG(INFO) << "Authorizing principal '" - << (principal.isSome() ? principal.get() : "ANY") + << (principal.isSome() ? stringify(principal.get()) : "ANY") << "' to GET the endpoint '" << path << "'"; return authorizer->authorized(authRequest); @@ -855,7 +884,7 @@ process::Future<bool> authorizeEndpoint( const string& endpoint, const string& method, const Option<Authorizer*>& authorizer, - const Option<string>& principal) + const Option<Principal>& principal) { if (authorizer.isNone()) { return true; @@ -876,14 +905,16 @@ process::Future<bool> authorizeEndpoint( "Endpoint '" + endpoint + "' is not an authorizable endpoint."); } - if (principal.isSome()) { - request.mutable_subject()->set_value(principal.get()); + Option<authorization::Subject> subject = + authorization::createSubject(principal); + if (subject.isSome()) { + request.mutable_subject()->CopyFrom(subject.get()); } request.mutable_object()->set_value(endpoint); LOG(INFO) << "Authorizing principal '" - << (principal.isSome() ? principal.get() : "ANY") + << (principal.isSome() ? stringify(principal.get()) : "ANY") << "' to " << method << " the '" << endpoint << "' endpoint"; http://git-wip-us.apache.org/repos/asf/mesos/blob/1b4f33fa/src/common/http.hpp ---------------------------------------------------------------------- diff --git a/src/common/http.hpp b/src/common/http.hpp index 3d5ab59..a3cfc5d 100644 --- a/src/common/http.hpp +++ b/src/common/http.hpp @@ -128,6 +128,15 @@ void json(JSON::ObjectWriter* writer, const Resources& resources); void json(JSON::ObjectWriter* writer, const Task& task); void json(JSON::ObjectWriter* writer, const TaskStatus& status); +namespace authorization { + +// Creates a subject for authorization purposes when given an authenticated +// principal. This function accepts and returns an `Option` to make call sites +// cleaner, since it is possible that `principal` will be `NONE`. +const Option<authorization::Subject> createSubject( + const Option<process::http::authentication::Principal>& principal); + +} // namespace authorization { const process::http::authorization::AuthorizationCallbacks createAuthorizationCallbacks(Authorizer* authorizer); @@ -182,7 +191,7 @@ process::Future<bool> authorizeEndpoint( const std::string& endpoint, const std::string& method, const Option<Authorizer*>& authorizer, - const Option<std::string>& principal); + const Option<process::http::authentication::Principal>& principal); bool approveViewRole(
