]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_auth.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_auth.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4
5 #ifndef CEPH_RGW_AUTH_H
6 #define CEPH_RGW_AUTH_H
7
8 #include <functional>
9 #include <ostream>
10 #include <type_traits>
11 #include <system_error>
12 #include <utility>
13
14 #include "rgw_common.h"
15 #include "rgw_keystone.h"
16 #include "rgw_web_idp.h"
17
18 #define RGW_USER_ANON_ID "anonymous"
19
20 namespace rgw {
21 namespace auth {
22
23 using Exception = std::system_error;
24
25
26 /* Load information about identity that will be used by RGWOp to authorize
27 * any operation that comes from an authenticated user. */
28 class Identity {
29 public:
30 typedef std::map<std::string, int> aclspec_t;
31 using idset_t = boost::container::flat_set<Principal>;
32
33 virtual ~Identity() = default;
34
35 /* Translate the ACL provided in @aclspec into concrete permission set that
36 * can be used during the authorization phase (RGWOp::verify_permission).
37 * On error throws rgw::auth::Exception storing the reason.
38 *
39 * NOTE: an implementation is responsible for giving the real semantic to
40 * the items in @aclspec. That is, their meaning may depend on particular
41 * applier that is being used. */
42 virtual uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const = 0;
43
44 /* Verify whether a given identity *can be treated as* an admin of rgw_user
45 * (account in Swift's terminology) specified in @uid. On error throws
46 * rgw::auth::Exception storing the reason. */
47 virtual bool is_admin_of(const rgw_user& uid) const = 0;
48
49 /* Verify whether a given identity *is* the owner of the rgw_user (account
50 * in the Swift's terminology) specified in @uid. On internal error throws
51 * rgw::auth::Exception storing the reason. */
52 virtual bool is_owner_of(const rgw_user& uid) const = 0;
53
54 /* Return the permission mask that is used to narrow down the set of
55 * operations allowed for a given identity. This method reflects the idea
56 * of subuser tied to RGWUserInfo. On error throws rgw::auth::Exception
57 * with the reason. */
58 virtual uint32_t get_perm_mask() const = 0;
59
60 virtual bool is_anonymous() const final {
61 /* If the identity owns the anonymous account (rgw_user), it's considered
62 * the anonymous identity. On error throws rgw::auth::Exception storing
63 * the reason. */
64 return is_owner_of(rgw_user(RGW_USER_ANON_ID));
65 }
66
67 virtual void to_str(std::ostream& out) const = 0;
68
69 /* Verify whether a given identity corresponds to an identity in the
70 provided set */
71 virtual bool is_identity(const idset_t& ids) const = 0;
72
73 /* Identity Type: RGW/ LDAP/ Keystone */
74 virtual uint32_t get_identity_type() const = 0;
75
76 /* Name of Account */
77 virtual string get_acct_name() const = 0;
78 };
79
80 inline std::ostream& operator<<(std::ostream& out,
81 const rgw::auth::Identity& id) {
82 id.to_str(out);
83 return out;
84 }
85
86
87 std::unique_ptr<Identity> transform_old_authinfo(const req_state* const s);
88
89
90 /* Interface for classes applying changes to request state/RADOS store
91 * imposed by a particular rgw::auth::Engine.
92 *
93 * In contrast to rgw::auth::Engine, implementations of this interface
94 * are allowed to handle req_state or RGWRados in the read-write manner.
95 *
96 * It's expected that most (if not all) of implementations will also
97 * conform to rgw::auth::Identity interface to provide authorization
98 * policy (ACLs, account's ownership and entitlement). */
99 class IdentityApplier : public Identity {
100 public:
101 typedef std::unique_ptr<IdentityApplier> aplptr_t;
102
103 virtual ~IdentityApplier() {};
104
105 /* Fill provided RGWUserInfo with information about the account that
106 * RGWOp will operate on. Errors are handled solely through exceptions.
107 *
108 * XXX: be aware that the "account" term refers to rgw_user. The naming
109 * is legacy. */
110 virtual void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const = 0; /* out */
111
112 /* Apply any changes to request state. This method will be most useful for
113 * TempURL of Swift API. */
114 virtual void modify_request_state(const DoutPrefixProvider* dpp, req_state* s) const {} /* in/out */
115 };
116
117
118 /* Interface class for completing the two-step authentication process.
119 * Completer provides the second step - the complete() method that should
120 * be called after Engine::authenticate() but before *committing* results
121 * of an RGWOp (or sending a response in the case of non-mutating ops).
122 *
123 * The motivation driving the interface is to address those authentication
124 * schemas that require message integrity verification *without* in-memory
125 * data buffering. Typical examples are AWS Auth v4 and the auth mechanism
126 * of browser uploads facilities both in S3 and Swift APIs (see RGWPostObj).
127 * The workflow of request from the authentication point-of-view does look
128 * like following one:
129 * A. authenticate (Engine::authenticate),
130 * B. authorize (see RGWOp::verify_permissions),
131 * C. execute-prepare (init potential data modifications),
132 * D. authenticate-complete - (Completer::complete),
133 * E. execute-commit - commit the modifications from point C. */
134 class Completer {
135 public:
136 /* It's expected that Completers would tend to implement many interfaces
137 * and be used not only in req_state::auth::completer. Ref counting their
138 * instances would be helpful. */
139 typedef std::shared_ptr<Completer> cmplptr_t;
140
141 virtual ~Completer() = default;
142
143 /* Complete the authentication process. Return boolean indicating whether
144 * the completion succeeded. On error throws rgw::auth::Exception storing
145 * the reason. */
146 virtual bool complete() = 0;
147
148 /* Apply any changes to request state. The initial use case was injecting
149 * the AWSv4 filter over rgw::io::RestfulClient in req_state. */
150 virtual void modify_request_state(const DoutPrefixProvider* dpp, req_state* s) = 0; /* in/out */
151 };
152
153
154 /* Interface class for authentication backends (auth engines) in RadosGW.
155 *
156 * An engine is supposed only to authenticate (not authorize!) requests
157 * basing on their req_state and - if access has been granted - provide
158 * an upper layer with:
159 * - rgw::auth::IdentityApplier to commit all changes to the request state as
160 * well as to the RADOS store (creating an account, synchronizing
161 * user-related information with external databases and so on).
162 * - rgw::auth::Completer (optionally) to finish the authentication
163 * of the request. Typical use case is verifying message integrity
164 * in AWS Auth v4 and browser uploads (RGWPostObj).
165 *
166 * Both of them are supposed to be wrapped in Engine::AuthResult.
167 *
168 * The authentication process consists of two steps:
169 * - Engine::authenticate() which should be called before *initiating*
170 * any modifications to RADOS store that are related to an operation
171 * a client wants to perform (RGWOp::execute).
172 * - Completer::complete() supposed to be called, if completer has been
173 * returned, after the authenticate() step but before *committing*
174 * those modifications or sending a response (RGWOp::complete).
175 *
176 * An engine outlives both Applier and Completer. It's intended to live
177 * since RadosGW's initialization and handle multiple requests till
178 * a reconfiguration.
179 *
180 * Auth engine MUST NOT make any changes to req_state nor RADOS store.
181 * This is solely an Applier's responsibility!
182 *
183 * Separation between authentication and global state modification has
184 * been introduced because many auth engines are orthogonal to appliers
185 * and thus they can be decoupled. Additional motivation is to clearly
186 * distinguish all portions of code modifying data structures. */
187 class Engine {
188 public:
189 virtual ~Engine() = default;
190
191 class AuthResult {
192 struct rejection_mark_t {};
193 bool is_rejected = false;
194 int reason = 0;
195
196 std::pair<IdentityApplier::aplptr_t, Completer::cmplptr_t> result_pair;
197
198 explicit AuthResult(const int reason)
199 : reason(reason) {
200 }
201
202 AuthResult(rejection_mark_t&&, const int reason)
203 : is_rejected(true),
204 reason(reason) {
205 }
206
207 /* Allow only the reasonable combintations - returning just Completer
208 * without accompanying IdentityApplier is strictly prohibited! */
209 explicit AuthResult(IdentityApplier::aplptr_t&& applier)
210 : result_pair(std::move(applier), nullptr) {
211 }
212
213 AuthResult(IdentityApplier::aplptr_t&& applier,
214 Completer::cmplptr_t&& completer)
215 : result_pair(std::move(applier), std::move(completer)) {
216 }
217
218 public:
219 enum class Status {
220 /* Engine doesn't grant the access but also doesn't reject it. */
221 DENIED,
222
223 /* Engine successfully authenicated requester. */
224 GRANTED,
225
226 /* Engine strictly indicates that a request should be rejected
227 * without trying any further engine. */
228 REJECTED
229 };
230
231 Status get_status() const {
232 if (is_rejected) {
233 return Status::REJECTED;
234 } else if (! result_pair.first) {
235 return Status::DENIED;
236 } else {
237 return Status::GRANTED;
238 }
239 }
240
241 int get_reason() const {
242 return reason;
243 }
244
245 IdentityApplier::aplptr_t get_applier() {
246 return std::move(result_pair.first);
247 }
248
249 Completer::cmplptr_t&& get_completer() {
250 return std::move(result_pair.second);
251 }
252
253 static AuthResult reject(const int reason = -EACCES) {
254 return AuthResult(rejection_mark_t(), reason);
255 }
256
257 static AuthResult deny(const int reason = -EACCES) {
258 return AuthResult(reason);
259 }
260
261 static AuthResult grant(IdentityApplier::aplptr_t&& applier) {
262 return AuthResult(std::move(applier));
263 }
264
265 static AuthResult grant(IdentityApplier::aplptr_t&& applier,
266 Completer::cmplptr_t&& completer) {
267 return AuthResult(std::move(applier), std::move(completer));
268 }
269 };
270
271 using result_t = AuthResult;
272
273 /* Get name of the auth engine. */
274 virtual const char* get_name() const noexcept = 0;
275
276 /* Throwing method for identity verification. When the check is positive
277 * an implementation should return Engine::result_t containing:
278 * - a non-null pointer to an object conforming the Applier interface.
279 * Otherwise, the authentication is treated as failed.
280 * - a (potentially null) pointer to an object conforming the Completer
281 * interface.
282 *
283 * On error throws rgw::auth::Exception containing the reason. */
284 virtual result_t authenticate(const DoutPrefixProvider* dpp, const req_state* s) const = 0;
285 };
286
287
288 /* Interface for extracting a token basing from data carried by req_state. */
289 class TokenExtractor {
290 public:
291 virtual ~TokenExtractor() = default;
292 virtual std::string get_token(const req_state* s) const = 0;
293 };
294
295
296 /* Abstract class for stacking sub-engines to expose them as a single
297 * Engine. It is responsible for ordering its sub-engines and managing
298 * fall-backs between them. Derivatee is supposed to encapsulate engine
299 * instances and add them using the add_engine() method in the order it
300 * wants to be tried during the call to authenticate().
301 *
302 * Each new Strategy should be exposed to StrategyRegistry for handling
303 * the dynamic reconfiguration. */
304 class Strategy : public Engine {
305 public:
306 /* Specifiers controlling what happens when an associated engine fails.
307 * The names and semantic has been borrowed mostly from libpam. */
308 enum class Control {
309 /* Failure of an engine injected with the REQUISITE specifier aborts
310 * the strategy's authentication process immediately. No other engine
311 * will be tried. */
312 REQUISITE,
313
314 /* Success of an engine injected with the SUFFICIENT specifier ends
315 * strategy's authentication process successfully. However, denying
316 * doesn't abort it -- there will be fall-back to following engine
317 * if the one that failed wasn't the last one. */
318 SUFFICIENT,
319
320 /* Like SUFFICIENT with the exception that on failure the reason code
321 * is not overridden. Instead, it's taken directly from the last tried
322 * non-FALLBACK engine. If there was no previous non-FALLBACK engine
323 * in a Strategy, then the result_t::deny(reason = -EACCES) is used. */
324 FALLBACK,
325 };
326
327 Engine::result_t authenticate(const DoutPrefixProvider* dpp, const req_state* s) const override final;
328
329 bool is_empty() const {
330 return auth_stack.empty();
331 }
332
333 static int apply(const DoutPrefixProvider* dpp, const Strategy& auth_strategy, req_state* s) noexcept;
334
335 private:
336 /* Using the reference wrapper here to explicitly point out we are not
337 * interested in storing nulls while preserving the dynamic polymorphism. */
338 using stack_item_t = std::pair<std::reference_wrapper<const Engine>,
339 Control>;
340 std::vector<stack_item_t> auth_stack;
341
342 protected:
343 void add_engine(Control ctrl_flag, const Engine& engine) noexcept;
344 };
345
346
347 /* A class aggregating the knowledge about all Strategies in RadosGW. It is
348 * responsible for handling the dynamic reconfiguration on e.g. realm update.
349 * The definition is in rgw/rgw_auth_registry.h,
350 *
351 * Each new Strategy should be exposed to it. */
352 class StrategyRegistry;
353
354 class WebIdentityApplier : public IdentityApplier {
355 protected:
356 CephContext* const cct;
357 RGWRados* const store;
358 rgw::web_idp::WebTokenClaims token_claims;
359
360 string get_idp_url() const;
361
362 public:
363 WebIdentityApplier( CephContext* const cct,
364 RGWRados* const store,
365 const rgw::web_idp::WebTokenClaims& token_claims)
366 : cct(cct),
367 store(store),
368 token_claims(token_claims) {
369 }
370
371 void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override {
372 user_info.user_id = rgw_user(token_claims.sub);
373 user_info.display_name = token_claims.user_name;
374 }
375
376 void modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const override;
377
378 uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override {
379 return RGW_PERM_NONE;
380 }
381
382 bool is_admin_of(const rgw_user& uid) const override {
383 return false;
384 }
385
386 bool is_owner_of(const rgw_user& uid) const override {
387 return false;
388 }
389
390 uint32_t get_perm_mask() const override {
391 return RGW_PERM_NONE;
392 }
393
394 void to_str(std::ostream& out) const override;
395
396 bool is_identity(const idset_t& ids) const override;
397
398 uint32_t get_identity_type() const override {
399 return TYPE_WEB;
400 }
401
402 string get_acct_name() const override {
403 return token_claims.user_name;
404 }
405
406 struct Factory {
407 virtual ~Factory() {}
408
409 virtual aplptr_t create_apl_web_identity( CephContext* cct,
410 const req_state* s,
411 const rgw::web_idp::WebTokenClaims& token) const = 0;
412 };
413 };
414
415 /* rgw::auth::RemoteApplier targets those authentication engines which don't
416 * need to ask the RADOS store while performing the auth process. Instead,
417 * they obtain credentials from an external source like Keystone or LDAP.
418 *
419 * As the authenticated user may not have an account yet, RGWRemoteAuthApplier
420 * must be able to create it basing on data passed by an auth engine. Those
421 * data will be used to fill RGWUserInfo structure. */
422 class RemoteApplier : public IdentityApplier {
423 public:
424 class AuthInfo {
425 friend class RemoteApplier;
426 protected:
427 const rgw_user acct_user;
428 const std::string acct_name;
429 const uint32_t perm_mask;
430 const bool is_admin;
431 const uint32_t acct_type;
432
433 public:
434 enum class acct_privilege_t {
435 IS_ADMIN_ACCT,
436 IS_PLAIN_ACCT
437 };
438
439 AuthInfo(const rgw_user& acct_user,
440 const std::string& acct_name,
441 const uint32_t perm_mask,
442 const acct_privilege_t level,
443 const uint32_t acct_type=TYPE_NONE)
444 : acct_user(acct_user),
445 acct_name(acct_name),
446 perm_mask(perm_mask),
447 is_admin(acct_privilege_t::IS_ADMIN_ACCT == level),
448 acct_type(acct_type) {
449 }
450 };
451
452 using aclspec_t = rgw::auth::Identity::aclspec_t;
453 typedef std::function<uint32_t(const aclspec_t&)> acl_strategy_t;
454
455 protected:
456 CephContext* const cct;
457
458 /* Read-write is intensional here due to RGWUserInfo creation process. */
459 RGWRados* const store;
460
461 /* Supplemental strategy for extracting permissions from ACLs. Its results
462 * will be combined (ORed) with a default strategy that is responsible for
463 * handling backward compatibility. */
464 const acl_strategy_t extra_acl_strategy;
465
466 const AuthInfo info;
467 const bool implicit_tenants;
468
469 virtual void create_account(const DoutPrefixProvider* dpp,
470 const rgw_user& acct_user,
471 RGWUserInfo& user_info) const; /* out */
472
473 public:
474 RemoteApplier(CephContext* const cct,
475 RGWRados* const store,
476 acl_strategy_t&& extra_acl_strategy,
477 const AuthInfo& info,
478 const bool implicit_tenants)
479 : cct(cct),
480 store(store),
481 extra_acl_strategy(std::move(extra_acl_strategy)),
482 info(info),
483 implicit_tenants(implicit_tenants) {
484 }
485
486 uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override;
487 bool is_admin_of(const rgw_user& uid) const override;
488 bool is_owner_of(const rgw_user& uid) const override;
489 bool is_identity(const idset_t& ids) const override;
490
491 uint32_t get_perm_mask() const override { return info.perm_mask; }
492 void to_str(std::ostream& out) const override;
493 void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override; /* out */
494 uint32_t get_identity_type() const override { return info.acct_type; }
495 string get_acct_name() const override { return info.acct_name; }
496
497 struct Factory {
498 virtual ~Factory() {}
499 /* Providing r-value reference here is required intensionally. Callee is
500 * thus disallowed to handle std::function in a way that could inhibit
501 * the move behaviour (like forgetting about std::moving a l-value). */
502 virtual aplptr_t create_apl_remote(CephContext* cct,
503 const req_state* s,
504 acl_strategy_t&& extra_acl_strategy,
505 const AuthInfo &info) const = 0;
506 };
507 };
508
509
510 /* rgw::auth::LocalApplier targets those auth engines that base on the data
511 * enclosed in the RGWUserInfo control structure. As a side effect of doing
512 * the authentication process, they must have it loaded. Leveraging this is
513 * a way to avoid unnecessary calls to underlying RADOS store. */
514 class LocalApplier : public IdentityApplier {
515 using aclspec_t = rgw::auth::Identity::aclspec_t;
516
517 protected:
518 const RGWUserInfo user_info;
519 const std::string subuser;
520 uint32_t perm_mask;
521
522 uint32_t get_perm_mask(const std::string& subuser_name,
523 const RGWUserInfo &uinfo) const;
524
525 public:
526 static const std::string NO_SUBUSER;
527
528 LocalApplier(CephContext* const cct,
529 const RGWUserInfo& user_info,
530 std::string subuser,
531 const boost::optional<uint32_t>& perm_mask)
532 : user_info(user_info),
533 subuser(std::move(subuser)) {
534 if (perm_mask) {
535 this->perm_mask = perm_mask.get();
536 } else {
537 this->perm_mask = RGW_PERM_INVALID;
538 }
539 }
540
541
542 uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override;
543 bool is_admin_of(const rgw_user& uid) const override;
544 bool is_owner_of(const rgw_user& uid) const override;
545 bool is_identity(const idset_t& ids) const override;
546 uint32_t get_perm_mask() const override {
547 if (this->perm_mask == RGW_PERM_INVALID) {
548 return get_perm_mask(subuser, user_info);
549 } else {
550 return this->perm_mask;
551 }
552 }
553 void to_str(std::ostream& out) const override;
554 void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override; /* out */
555 uint32_t get_identity_type() const override { return TYPE_RGW; }
556 string get_acct_name() const override { return {}; }
557
558 struct Factory {
559 virtual ~Factory() {}
560 virtual aplptr_t create_apl_local(CephContext* cct,
561 const req_state* s,
562 const RGWUserInfo& user_info,
563 const std::string& subuser,
564 const boost::optional<uint32_t>& perm_mask) const = 0;
565 };
566 };
567
568 class RoleApplier : public IdentityApplier {
569 protected:
570 const string role_name;
571 const rgw_user user_id;
572 vector<std::string> role_policies;
573
574 public:
575
576 RoleApplier(CephContext* const cct,
577 const string& role_name,
578 const rgw_user& user_id,
579 const vector<std::string>& role_policies)
580 : role_name(role_name),
581 user_id(user_id),
582 role_policies(role_policies) {}
583
584 uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override {
585 return 0;
586 }
587 bool is_admin_of(const rgw_user& uid) const override {
588 return false;
589 }
590 bool is_owner_of(const rgw_user& uid) const override {
591 return false;
592 }
593 bool is_identity(const idset_t& ids) const override;
594 uint32_t get_perm_mask() const override {
595 return RGW_PERM_NONE;
596 }
597 void to_str(std::ostream& out) const override;
598 void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override; /* out */
599 uint32_t get_identity_type() const override { return TYPE_ROLE; }
600 string get_acct_name() const override { return {}; }
601 void modify_request_state(const DoutPrefixProvider* dpp, req_state* s) const override;
602
603 struct Factory {
604 virtual ~Factory() {}
605 virtual aplptr_t create_apl_role( CephContext* cct,
606 const req_state* s,
607 const string& role_name,
608 const rgw_user& user_id,
609 const vector<std::string>& role_policies) const = 0;
610 };
611 };
612
613 /* The anonymous abstract engine. */
614 class AnonymousEngine : public Engine {
615 CephContext* const cct;
616 const rgw::auth::LocalApplier::Factory* const apl_factory;
617
618 public:
619 AnonymousEngine(CephContext* const cct,
620 const rgw::auth::LocalApplier::Factory* const apl_factory)
621 : cct(cct),
622 apl_factory(apl_factory) {
623 }
624
625 const char* get_name() const noexcept override {
626 return "rgw::auth::AnonymousEngine";
627 }
628
629 Engine::result_t authenticate(const DoutPrefixProvider* dpp, const req_state* s) const override final;
630
631 protected:
632 virtual bool is_applicable(const req_state*) const noexcept {
633 return true;
634 }
635 };
636
637 } /* namespace auth */
638 } /* namespace rgw */
639
640
641 uint32_t rgw_perms_from_aclspec_default_strategy(
642 const rgw_user& uid,
643 const rgw::auth::Identity::aclspec_t& aclspec);
644
645 #endif /* CEPH_RGW_AUTH_H */