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