]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_auth.h
update sources to 12.2.7
[ceph.git] / ceph / src / rgw / rgw_auth.h
CommitLineData
7c673cae
FG
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
7c673cae
FG
19namespace rgw {
20namespace auth {
21
22using 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. */
27class Identity {
28public:
29 typedef std::map<std::string, int> aclspec_t;
31f18b77 30 using idset_t = boost::container::flat_set<Principal>;
7c673cae
FG
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;
31f18b77
FG
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;
7c673cae
FG
71};
72
73inline std::ostream& operator<<(std::ostream& out,
74 const rgw::auth::Identity& id) {
75 id.to_str(out);
76 return out;
77}
78
79
80std::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). */
92class IdentityApplier : public Identity {
93public:
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
31f18b77
FG
106 * TempURL of Swift API. */
107 virtual void modify_request_state(req_state* s) const {} /* in/out */
7c673cae
FG
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. */
127class Completer {
128public:
31f18b77
FG
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;
7c673cae
FG
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;
31f18b77
FG
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 */
7c673cae
FG
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. */
180class Engine {
181public:
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. */
282class TokenExtractor {
283public:
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. */
297class Strategy : public Engine {
298public:
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
31f18b77
FG
326 static int apply(const Strategy& auth_strategy, req_state* s) noexcept;
327
7c673cae
FG
328private:
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
335protected:
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. */
345class StrategyRegistry;
346
28e407b8
AA
347class ImplicitTenants: public md_config_obs_t {
348public:
349 enum implicit_tenant_flag_bits {IMPLICIT_TENANTS_SWIFT=1,
350 IMPLICIT_TENANTS_S3=2, IMPLICIT_TENANTS_BAD = -1, };
351private:
352 int saved;
353 void recompute_value(const md_config_t *);
354 class ImplicitTenantValue {
355 friend class ImplicitTenants;
356 int v;
357 ImplicitTenantValue(int v) : v(v) {};
358 public:
359 bool inline is_split_mode()
360 {
361 assert(v != IMPLICIT_TENANTS_BAD);
362 return v == IMPLICIT_TENANTS_SWIFT || v == IMPLICIT_TENANTS_S3;
363 }
364 bool inline implicit_tenants_for_(const implicit_tenant_flag_bits bit)
365 {
366 assert(v != IMPLICIT_TENANTS_BAD);
367 return !!(v&bit);
368 }
369 };
370public:
371 ImplicitTenants(md_config_t &c) { recompute_value(&c);}
372 ImplicitTenantValue get_value() {
373 return ImplicitTenantValue(saved);
374 }
375private:
376 const char** get_tracked_conf_keys() const override;
377 void handle_conf_change(const struct md_config_t *conf,
378 const std::set <std::string> &changed) override;
379};
380
381std::tuple<bool,bool> implicit_tenants_enabled_for_swift(CephContext * const cct);
382std::tuple<bool,bool> implicit_tenants_enabled_for_s3(CephContext * const cct);
383
7c673cae
FG
384/* rgw::auth::RemoteApplier targets those authentication engines which don't
385 * need to ask the RADOS store while performing the auth process. Instead,
386 * they obtain credentials from an external source like Keystone or LDAP.
387 *
388 * As the authenticated user may not have an account yet, RGWRemoteAuthApplier
389 * must be able to create it basing on data passed by an auth engine. Those
390 * data will be used to fill RGWUserInfo structure. */
391class RemoteApplier : public IdentityApplier {
392public:
393 class AuthInfo {
394 friend class RemoteApplier;
395 protected:
396 const rgw_user acct_user;
397 const std::string acct_name;
398 const uint32_t perm_mask;
399 const bool is_admin;
400 const uint32_t acct_type;
401
402 public:
403 enum class acct_privilege_t {
404 IS_ADMIN_ACCT,
405 IS_PLAIN_ACCT
406 };
407
408 AuthInfo(const rgw_user& acct_user,
409 const std::string& acct_name,
410 const uint32_t perm_mask,
411 const acct_privilege_t level,
412 const uint32_t acct_type=TYPE_NONE)
413 : acct_user(acct_user),
414 acct_name(acct_name),
415 perm_mask(perm_mask),
416 is_admin(acct_privilege_t::IS_ADMIN_ACCT == level),
417 acct_type(acct_type) {
418 }
419 };
420
421 using aclspec_t = rgw::auth::Identity::aclspec_t;
422 typedef std::function<uint32_t(const aclspec_t&)> acl_strategy_t;
423
424protected:
425 CephContext* const cct;
426
427 /* Read-write is intensional here due to RGWUserInfo creation process. */
428 RGWRados* const store;
429
430 /* Supplemental strategy for extracting permissions from ACLs. Its results
431 * will be combined (ORed) with a default strategy that is responsible for
432 * handling backward compatibility. */
433 const acl_strategy_t extra_acl_strategy;
434
435 const AuthInfo info;
28e407b8
AA
436 rgw::auth::ImplicitTenants& implicit_tenant_context;
437 const rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit;
7c673cae
FG
438
439 virtual void create_account(const rgw_user& acct_user,
28e407b8 440 bool implicit_tenant,
7c673cae
FG
441 RGWUserInfo& user_info) const; /* out */
442
443public:
444 RemoteApplier(CephContext* const cct,
445 RGWRados* const store,
446 acl_strategy_t&& extra_acl_strategy,
447 const AuthInfo& info,
28e407b8
AA
448 rgw::auth::ImplicitTenants& implicit_tenant_context,
449 rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit)
7c673cae
FG
450 : cct(cct),
451 store(store),
452 extra_acl_strategy(std::move(extra_acl_strategy)),
453 info(info),
28e407b8
AA
454 implicit_tenant_context(implicit_tenant_context),
455 implicit_tenant_bit(implicit_tenant_bit) {
7c673cae
FG
456 }
457
458 uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override;
459 bool is_admin_of(const rgw_user& uid) const override;
460 bool is_owner_of(const rgw_user& uid) const override;
31f18b77
FG
461 bool is_identity(const idset_t& ids) const override;
462
7c673cae
FG
463 uint32_t get_perm_mask() const override { return info.perm_mask; }
464 void to_str(std::ostream& out) const override;
465 void load_acct_info(RGWUserInfo& user_info) const override; /* out */
466
467 struct Factory {
468 virtual ~Factory() {}
469 /* Providing r-value reference here is required intensionally. Callee is
470 * thus disallowed to handle std::function in a way that could inhibit
471 * the move behaviour (like forgetting about std::moving a l-value). */
472 virtual aplptr_t create_apl_remote(CephContext* cct,
473 const req_state* s,
474 acl_strategy_t&& extra_acl_strategy,
475 const AuthInfo info) const = 0;
476 };
477};
478
479
480/* rgw::auth::LocalApplier targets those auth engines that base on the data
481 * enclosed in the RGWUserInfo control structure. As a side effect of doing
482 * the authentication process, they must have it loaded. Leveraging this is
483 * a way to avoid unnecessary calls to underlying RADOS store. */
484class LocalApplier : public IdentityApplier {
485 using aclspec_t = rgw::auth::Identity::aclspec_t;
486
487protected:
488 const RGWUserInfo user_info;
489 const std::string subuser;
490
491 uint32_t get_perm_mask(const std::string& subuser_name,
492 const RGWUserInfo &uinfo) const;
493
494public:
495 static const std::string NO_SUBUSER;
496
497 LocalApplier(CephContext* const cct,
498 const RGWUserInfo& user_info,
499 std::string subuser)
500 : user_info(user_info),
501 subuser(std::move(subuser)) {
502 }
503
504
505 uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override;
506 bool is_admin_of(const rgw_user& uid) const override;
507 bool is_owner_of(const rgw_user& uid) const override;
31f18b77 508 bool is_identity(const idset_t& ids) const override;
7c673cae
FG
509 uint32_t get_perm_mask() const override {
510 return get_perm_mask(subuser, user_info);
511 }
512 void to_str(std::ostream& out) const override;
513 void load_acct_info(RGWUserInfo& user_info) const override; /* out */
514
515 struct Factory {
516 virtual ~Factory() {}
517 virtual aplptr_t create_apl_local(CephContext* cct,
518 const req_state* s,
519 const RGWUserInfo& user_info,
520 const std::string& subuser) const = 0;
521 };
522};
523
524
525/* The anonymous abstract engine. */
526class AnonymousEngine : public Engine {
527 CephContext* const cct;
528 const rgw::auth::LocalApplier::Factory* const apl_factory;
529
530public:
531 AnonymousEngine(CephContext* const cct,
532 const rgw::auth::LocalApplier::Factory* const apl_factory)
533 : cct(cct),
534 apl_factory(apl_factory) {
535 }
536
537 const char* get_name() const noexcept override {
538 return "rgw::auth::AnonymousEngine";
539 }
540
541 Engine::result_t authenticate(const req_state* s) const override final;
542
543protected:
544 virtual bool is_applicable(const req_state*) const noexcept {
545 return true;
546 }
547};
548
549} /* namespace auth */
550} /* namespace rgw */
551
552
553uint32_t rgw_perms_from_aclspec_default_strategy(
554 const rgw_user& uid,
555 const rgw::auth::Identity::aclspec_t& aclspec);
556
557#endif /* CEPH_RGW_AUTH_H */