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 DomainInfo& domainInfo);
158 void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo);
159 void json(
160  JSON::StringWriter* writer, const FrameworkInfo::Capability& capability);
161 void json(JSON::ArrayWriter* writer, const Labels& labels);
162 void json(JSON::ObjectWriter* writer, const MasterInfo& info);
163 void json(
164  JSON::StringWriter* writer, const MasterInfo::Capability& capability);
165 void json(JSON::ObjectWriter* writer, const Offer& offer);
166 void json(JSON::ObjectWriter* writer, const Resources& resources);
167 void json(
168  JSON::ObjectWriter* writer,
169  const google::protobuf::RepeatedPtrField<Resource>& resources);
170 void json(JSON::ObjectWriter* writer, const SlaveInfo& slaveInfo);
171 void json(
172  JSON::StringWriter* writer, const SlaveInfo::Capability& capability);
173 void json(JSON::ObjectWriter* writer, const Task& task);
174 void json(JSON::ObjectWriter* writer, const TaskStatus& status);
175 
176 namespace authorization {
177 
178 // Creates a subject for authorization purposes when given an authenticated
179 // principal. This function accepts and returns an `Option` to make call sites
180 // cleaner, since it is possible that `principal` will be `NONE`.
183 
184 } // namespace authorization {
185 
188 
189 
190 // Implementation of the `ObjectApprover` interface authorizing all objects.
192 {
193 public:
195  const Option<ObjectApprover::Object>& object) const noexcept override
196  {
197  return true;
198  }
199 };
200 
201 
203 {
204 public:
206  const Option<Authorizer*>& authorizer,
208  std::initializer_list<authorization::Action> actions);
209 
210  template <authorization::Action action, typename... Args>
211  bool approved(const Args&... args)
212  {
213  if (!approvers.contains(action)) {
214  LOG(WARNING) << "Attempted to authorize " << principal
215  << " for unexpected action " << stringify(action);
216  return false;
217  }
218 
219  Try<bool> approved = approvers[action]->approved(
220  ObjectApprover::Object(args...));
221 
222  if (approved.isError()) {
223  // TODO(joerg84): Expose these errors back to the caller.
224  LOG(WARNING) << "Failed to authorize principal " << principal
225  << "for action " << stringify(action) << ": "
226  << approved.error();
227  return false;
228  }
229 
230  return approved.get();
231  }
232 
233 private:
235  hashmap<
236  authorization::Action,
237  process::Owned<ObjectApprover>>&& _approvers,
239  : approvers(std::move(_approvers)),
240  principal(_principal.isSome()
241  ? "'" + stringify(_principal.get()) + "'"
242  : "")
243  {}
244 
246  const std::string principal; // Only used for logging.
247 };
248 
249 
250 template <>
251 inline bool ObjectApprovers::approved<authorization::VIEW_ROLE>(
252  const Resource& resource)
253 {
254  // Necessary because recovered agents are presented in old format.
255  if (resource.has_role() && resource.role() != "*" &&
256  !approved<authorization::VIEW_ROLE>(resource.role())) {
257  return false;
258  }
259 
260  // Reservations follow a path model where each entry is a child of the
261  // previous one. Therefore, to accept the resource the acceptor has to
262  // accept all entries.
263  foreach (Resource::ReservationInfo reservation, resource.reservations()) {
264  if (!approved<authorization::VIEW_ROLE>(reservation.role())) {
265  return false;
266  }
267  }
268 
269  if (resource.has_allocation_info() &&
270  !approved<authorization::VIEW_ROLE>(
271  resource.allocation_info().role())) {
272  return false;
273  }
274 
275  return true;
276 }
277 
278 
284 template <typename T>
286 {
287 public:
289  {
290  if (id.isSome()) {
291  T targetId_;
292  targetId_.set_value(id.get());
293  targetId = targetId_;
294  }
295  }
296 
297  bool accept(const T& candidateId) const
298  {
299  if (targetId.isNone()) {
300  return true;
301  }
302 
303  return candidateId.value() == targetId->value();
304  }
305 
306 protected:
308 };
309 
310 
311 // Authorizes access to an HTTP endpoint. The `method` parameter
312 // determines which ACL action will be used in the authorization.
313 // It is expected that the caller has validated that `method` is
314 // supported by this function. Currently "GET" is supported.
315 //
316 // TODO(nfnt): Prefer types instead of strings
317 // for `endpoint` and `method`, see MESOS-5300.
319  const std::string& endpoint,
320  const std::string& method,
321  const Option<Authorizer*>& authorizer,
323 
324 
338  const std::string& realm,
339  const std::vector<std::string>& httpAuthenticatorNames,
340  const Option<Credentials>& credentials = None(),
341  const Option<std::string>& jwtSecretKey = None());
342 
343 
344 // Logs the request. Route handlers can compose this with the
345 // desired request handler to get consistent request logging.
347 
348 } // namespace mesos {
349 
350 #endif // __COMMON_HTTP_HPP__
size_t result_type
Definition: http.hpp:48
Definition: http.hpp:191
ContentType accept
Definition: http.hpp:89
ContentType
Definition: http.hpp:43
Definition: errorbase.hpp:36
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:81
Definition: type_utils.hpp:510
Definition: json.hpp:198
result_type operator()(const argument_type &action) const
Definition: http.hpp:52
Capability
Definition: capabilities.hpp:35
Definition: jsonify.hpp:254
Option< T > targetId
Definition: http.hpp:307
bool isSome() const
Definition: option.hpp:115
Definition: http.hpp:517
Definition: json.hpp:158
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:285
Try< Message > deserialize(ContentType contentType, const std::string &body)
Definition: http.hpp:107
Definition: http.hpp:86
void json(JSON::ObjectWriter *writer, const TaskStatus &status)
Definition: spec.hpp:26
Definition: http.hpp:202
Definition: jsonify.hpp:325
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:297
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:978
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.
#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:288
Option< ContentType > messageAccept
Definition: http.hpp:91
bool approved(const Args &...args)
Definition: http.hpp:211
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
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:194
Definition: jsonify.hpp:295
Definition: future.hpp:58
Definition: attributes.hpp:32