Apache Mesos
http.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __COMMON_HTTP_HPP__
18 #define __COMMON_HTTP_HPP__
19 
20 #include <vector>
21 
22 #include <mesos/http.hpp>
23 #include <mesos/mesos.hpp>
24 
26 
27 #include <mesos/quota/quota.hpp>
28 
30 #include <process/future.hpp>
31 #include <process/http.hpp>
32 #include <process/owned.hpp>
33 
34 #include <stout/hashmap.hpp>
35 #include <stout/hashset.hpp>
36 #include <stout/json.hpp>
37 #include <stout/jsonify.hpp>
38 #include <stout/protobuf.hpp>
39 #include <stout/unreachable.hpp>
40 
41 // TODO(benh): Remove this once we get C++14 as an enum should have a
42 // default hash.
43 namespace std {
44 
45 template <>
46 struct hash<mesos::authorization::Action>
47 {
48  typedef size_t result_type;
49 
50  typedef mesos::authorization::Action argument_type;
51 
52  result_type operator()(const argument_type& action) const
53  {
54  size_t seed = 0;
55  boost::hash_combine(
56  seed, static_cast<std::underlying_type<argument_type>::type>(action));
57  return seed;
58  }
59 };
60 
61 } // namespace std {
62 
63 namespace mesos {
64 
65 class Attributes;
66 class Resources;
67 class Task;
68 
69 namespace internal {
70 
71 // Name of the default, basic authenticator.
72 constexpr char DEFAULT_BASIC_HTTP_AUTHENTICATOR[] = "basic";
73 
74 // Name of the default, basic authenticatee.
75 constexpr char DEFAULT_BASIC_HTTP_AUTHENTICATEE[] = "basic";
76 
77 // Name of the default, JWT authenticator.
78 constexpr char DEFAULT_JWT_HTTP_AUTHENTICATOR[] = "jwt";
79 
81 
82 
83 // Contains the media types corresponding to some of the "Content-*",
84 // "Accept-*" and "Message-*" prefixed request headers in our internal
85 // representation.
87 {
88  ContentType content; // 'Content-Type' header.
89  ContentType accept; // 'Accept' header.
90  Option<ContentType> messageContent; // 'Message-Content-Type' header.
91  Option<ContentType> messageAccept; // 'Message-Accept' header.
92 };
93 
94 
95 // Serializes a protobuf message for transmission
96 // based on the HTTP content type.
97 // NOTE: For streaming `contentType`, `message` would not
98 // be serialized in "Record-IO" format.
99 std::string serialize(
100  ContentType contentType,
101  const google::protobuf::Message& message);
102 
103 
104 // Deserializes a string message into a protobuf message based on the
105 // HTTP content type.
106 template <typename Message>
108  ContentType contentType,
109  const std::string& body)
110 {
111  switch (contentType) {
112  case ContentType::PROTOBUF: {
113  Message message;
114  if (!message.ParseFromString(body)) {
115  return Error("Failed to parse body into a protobuf object");
116  }
117  return message;
118  }
119  case ContentType::JSON: {
120  Try<JSON::Value> value = JSON::parse(body);
121  if (value.isError()) {
122  return Error("Failed to parse body into JSON: " + value.error());
123  }
124 
125  return ::protobuf::parse<Message>(value.get());
126  }
127  case ContentType::RECORDIO: {
128  return Error("Deserializing a RecordIO stream is not supported");
129  }
130  }
131 
132  UNREACHABLE();
133 }
134 
135 
136 // Returns true if the media type can be used for
137 // streaming requests/responses.
138 bool streamingMediaType(ContentType contentType);
139 
140 
141 JSON::Object model(const Resources& resources);
143 JSON::Object model(const Attributes& attributes);
144 JSON::Object model(const CommandInfo& command);
145 JSON::Object model(const ExecutorInfo& executorInfo);
146 JSON::Array model(const Labels& labels);
147 JSON::Object model(const Task& task);
148 JSON::Object model(const FileInfo& fileInfo);
149 JSON::Object model(const quota::QuotaInfo& quotaInfo);
150 
151 void json(JSON::ObjectWriter* writer, const Task& task);
152 
153 } // namespace internal {
154 
155 void json(JSON::ObjectWriter* writer, const Attributes& attributes);
156 void json(JSON::ObjectWriter* writer, const CommandInfo& command);
157 void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo);
158 void json(JSON::ArrayWriter* writer, const Labels& labels);
159 void json(JSON::ObjectWriter* writer, const Resources& resources);
160 void json(JSON::ObjectWriter* writer, const Task& task);
161 void json(JSON::ObjectWriter* writer, const TaskStatus& status);
162 void json(JSON::ObjectWriter* writer, const DomainInfo& domainInfo);
163 
164 namespace authorization {
165 
166 // Creates a subject for authorization purposes when given an authenticated
167 // principal. This function accepts and returns an `Option` to make call sites
168 // cleaner, since it is possible that `principal` will be `NONE`.
171 
172 } // namespace authorization {
173 
176 
177 
178 // Implementation of the `ObjectApprover` interface authorizing all objects.
180 {
181 public:
183  const Option<ObjectApprover::Object>& object) const noexcept override
184  {
185  return true;
186  }
187 };
188 
189 
191 {
192 public:
194  const Option<Authorizer*>& authorizer,
196  std::initializer_list<authorization::Action> actions);
197 
198  template <authorization::Action action, typename... Args>
199  bool approved(const Args&... args)
200  {
201  if (!approvers.contains(action)) {
202  LOG(WARNING) << "Attempted to authorize "
203  << (principal.isSome()
204  ? "'" + stringify(principal.get()) + "'"
205  : "")
206  << " for unexpected action " << stringify(action);
207  return false;
208  }
209 
210  Try<bool> approved = approvers[action]->approved(
211  ObjectApprover::Object(args...));
212 
213  if (approved.isError()) {
214  // TODO(joerg84): Expose these errors back to the caller.
215  LOG(WARNING) << "Failed to authorize principal "
216  << (principal.isSome()
217  ? "'" + stringify(principal.get()) + "' "
218  : "")
219  << "for action " << stringify(action) << ": "
220  << approved.error();
221  return false;
222  }
223 
224  return approved.get();
225  }
226 
227 private:
229  hashmap<
230  authorization::Action,
231  process::Owned<ObjectApprover>>&& _approvers,
233  : approvers(std::move(_approvers)), principal(_principal) {}
234 
237 };
238 
239 
240 template <>
241 inline bool ObjectApprovers::approved<authorization::VIEW_ROLE>(
242  const Resource& resource)
243 {
244  // Necessary because recovered agents are presented in old format.
245  if (resource.has_role() && resource.role() != "*" &&
246  !approved<authorization::VIEW_ROLE>(resource.role())) {
247  return false;
248  }
249 
250  // Reservations follow a path model where each entry is a child of the
251  // previous one. Therefore, to accept the resource the acceptor has to
252  // accept all entries.
253  foreach (Resource::ReservationInfo reservation, resource.reservations()) {
254  if (!approved<authorization::VIEW_ROLE>(reservation.role())) {
255  return false;
256  }
257  }
258 
259  if (resource.has_allocation_info() &&
260  !approved<authorization::VIEW_ROLE>(
261  resource.allocation_info().role())) {
262  return false;
263  }
264 
265  return true;
266 }
267 
268 
274 template <typename T>
276 {
277 public:
279  {
280  if (id.isSome()) {
281  T targetId_;
282  targetId_.set_value(id.get());
283  targetId = targetId_;
284  }
285  }
286 
287  bool accept(const T& candidateId) const
288  {
289  if (targetId.isNone()) {
290  return true;
291  }
292 
293  return candidateId.value() == targetId->value();
294  }
295 
296 protected:
298 };
299 
300 
301 // Authorizes access to an HTTP endpoint. The `method` parameter
302 // determines which ACL action will be used in the authorization.
303 // It is expected that the caller has validated that `method` is
304 // supported by this function. Currently "GET" is supported.
305 //
306 // TODO(nfnt): Prefer types instead of strings
307 // for `endpoint` and `method`, see MESOS-5300.
309  const std::string& endpoint,
310  const std::string& method,
311  const Option<Authorizer*>& authorizer,
313 
314 
328  const std::string& realm,
329  const std::vector<std::string>& httpAuthenticatorNames,
330  const Option<Credentials>& credentials = None(),
331  const Option<std::string>& jwtSecretKey = None());
332 
333 
334 // Logs the request. Route handlers can compose this with the
335 // desired request handler to get consistent request logging.
337 
338 } // namespace mesos {
339 
340 #endif // __COMMON_HTTP_HPP__
size_t result_type
Definition: http.hpp:48
Definition: http.hpp:179
ContentType accept
Definition: http.hpp:89
ContentType
Definition: http.hpp:43
Definition: errorbase.hpp:36
virtual Try< bool > approved(const Option< ObjectApprover::Object > &object) const noexceptoverride
NOTE: As this function can be used synchronously by actors it is essential that it does not block! ...
Definition: http.hpp:182
Future< Response > request(const Request &request, bool streamedResponse=false)
Asynchronously sends an HTTP request to the process and returns the HTTP response once the entire res...
const Option< authorization::Subject > createSubject(const Option< process::http::authentication::Principal > &principal)
T & get()&
Definition: try.hpp:73
Definition: authorizer.hpp:46
Definition: check.hpp:33
bool streamingMediaType(ContentType contentType)
constexpr char DEFAULT_BASIC_HTTP_AUTHENTICATEE[]
Definition: http.hpp:75
JSON::Object model(const quota::QuotaInfo &quotaInfo)
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: resources.hpp:79
Definition: type_utils.hpp:510
Definition: json.hpp:194
result_type operator()(const argument_type &action) const
Definition: http.hpp:52
Option< T > targetId
Definition: http.hpp:297
bool isSome() const
Definition: option.hpp:115
Definition: http.hpp:517
Definition: json.hpp:154
Definition: hashmap.hpp:38
constexpr char DEFAULT_JWT_HTTP_AUTHENTICATOR[]
Definition: http.hpp:78
This interface is used to enable an identity service or any other back end to check authorization pol...
Definition: authorizer.hpp:243
void logRequest(const process::http::Request &request)
Used to filter results for API handlers.
Definition: http.hpp:275
Try< Message > deserialize(ContentType contentType, const std::string &body)
Definition: http.hpp:107
Definition: http.hpp:86
Definition: spec.hpp:30
Definition: http.hpp:190
Definition: jsonify.hpp:418
Option< Error > quotaInfo(const mesos::quota::QuotaInfo &quotaInfo)
const T & get() const &
Definition: option.hpp:118
hashset< std::string > AUTHORIZABLE_ENDPOINTS
bool accept(const T &candidateId) const
Definition: http.hpp:287
Try< Value > parse(const std::string &s)
Returns the OCI v1 descriptor, image index, image manifest and image configuration from the given str...
Definition: json.hpp:884
ContentType content
Definition: http.hpp:88
Option< ContentType > messageContent
Definition: http.hpp:90
static Try error(const E &e)
Definition: try.hpp:42
Try< Nothing > initializeHttpAuthenticators(const std::string &realm, const std::vector< std::string > &httpAuthenticatorNames, const Option< Credentials > &credentials=None(), const Option< std::string > &jwtSecretKey=None())
Helper function to create HTTP authenticators for a given realm and register in libprocess.
void json(JSON::ObjectWriter *writer, const DomainInfo &domainInfo)
#define UNREACHABLE()
Definition: unreachable.hpp:22
const process::http::authorization::AuthorizationCallbacks createAuthorizationCallbacks(Authorizer *authorizer)
constexpr char DEFAULT_BASIC_HTTP_AUTHENTICATOR[]
Definition: http.hpp:72
Definition: none.hpp:27
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:71
Try< uint32_t > type(const std::string &path)
IDAcceptor(const Option< std::string > &id=None())
Definition: http.hpp:278
Option< ContentType > messageAccept
Definition: http.hpp:91
bool approved(const Args &...args)
Definition: http.hpp:199
Try< Nothing > create(const std::string &hierarchy, const std::string &cgroup, bool recursive=false)
std::string serialize(ContentType contentType, const google::protobuf::Message &message)
process::Future< bool > authorizeEndpoint(const std::string &endpoint, const std::string &method, const Option< Authorizer * > &authorizer, const Option< process::http::authentication::Principal > &principal)
This interface represents a function object returned by the authorizer which can be used locally (and...
Definition: authorizer.hpp:40
std::string stringify(int flags)
Definition: owned.hpp:36
mesos::authorization::Action argument_type
Definition: http.hpp:50
Definition: jsonify.hpp:384
Definition: future.hpp:58
Definition: attributes.hpp:32