1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
5 #ifndef CEPH_RGW_AUTH_H
6 #define CEPH_RGW_AUTH_H
10 #include <type_traits>
11 #include <system_error>
14 #include "rgw_common.h"
15 #include "rgw_web_idp.h"
17 #define RGW_USER_ANON_ID "anonymous"
24 using Exception
= std::system_error
;
27 /* Load information about identity that will be used by RGWOp to authorize
28 * any operation that comes from an authenticated user. */
31 typedef std::map
<std::string
, int> aclspec_t
;
32 using idset_t
= boost::container::flat_set
<Principal
>;
34 virtual ~Identity() = default;
36 /* Translate the ACL provided in @aclspec into concrete permission set that
37 * can be used during the authorization phase (RGWOp::verify_permission).
38 * On error throws rgw::auth::Exception storing the reason.
40 * NOTE: an implementation is responsible for giving the real semantic to
41 * the items in @aclspec. That is, their meaning may depend on particular
42 * applier that is being used. */
43 virtual uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const = 0;
45 /* Verify whether a given identity *can be treated as* an admin of rgw_user
46 * (account in Swift's terminology) specified in @uid. On error throws
47 * rgw::auth::Exception storing the reason. */
48 virtual bool is_admin_of(const rgw_user
& uid
) const = 0;
50 /* Verify whether a given identity *is* the owner of the rgw_user (account
51 * in the Swift's terminology) specified in @uid. On internal error throws
52 * rgw::auth::Exception storing the reason. */
53 virtual bool is_owner_of(const rgw_user
& uid
) const = 0;
55 /* Return the permission mask that is used to narrow down the set of
56 * operations allowed for a given identity. This method reflects the idea
57 * of subuser tied to RGWUserInfo. On error throws rgw::auth::Exception
59 virtual uint32_t get_perm_mask() const = 0;
61 virtual bool is_anonymous() const {
62 /* If the identity owns the anonymous account (rgw_user), it's considered
63 * the anonymous identity. On error throws rgw::auth::Exception storing
65 return is_owner_of(rgw_user(RGW_USER_ANON_ID
));
68 virtual void to_str(std::ostream
& out
) const = 0;
70 /* Verify whether a given identity corresponds to an identity in the
72 virtual bool is_identity(const idset_t
& ids
) const = 0;
74 /* Identity Type: RGW/ LDAP/ Keystone */
75 virtual uint32_t get_identity_type() const = 0;
78 virtual string
get_acct_name() const = 0;
80 /* Subuser of Account */
81 virtual string
get_subuser() const = 0;
84 inline std::ostream
& operator<<(std::ostream
& out
,
85 const rgw::auth::Identity
& id
) {
91 std::unique_ptr
<rgw::auth::Identity
>
92 transform_old_authinfo(CephContext
* const cct
,
93 const rgw_user
& auth_id
,
97 std::unique_ptr
<Identity
> transform_old_authinfo(const req_state
* const s
);
100 /* Interface for classes applying changes to request state/RADOS store
101 * imposed by a particular rgw::auth::Engine.
103 * In contrast to rgw::auth::Engine, implementations of this interface
104 * are allowed to handle req_state or RGWUserCtl in the read-write manner.
106 * It's expected that most (if not all) of implementations will also
107 * conform to rgw::auth::Identity interface to provide authorization
108 * policy (ACLs, account's ownership and entitlement). */
109 class IdentityApplier
: public Identity
{
111 typedef std::unique_ptr
<IdentityApplier
> aplptr_t
;
113 virtual ~IdentityApplier() {};
115 /* Fill provided RGWUserInfo with information about the account that
116 * RGWOp will operate on. Errors are handled solely through exceptions.
118 * XXX: be aware that the "account" term refers to rgw_user. The naming
120 virtual void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const = 0; /* out */
122 /* Apply any changes to request state. This method will be most useful for
123 * TempURL of Swift API. */
124 virtual void modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* s
) const {} /* in/out */
128 /* Interface class for completing the two-step authentication process.
129 * Completer provides the second step - the complete() method that should
130 * be called after Engine::authenticate() but before *committing* results
131 * of an RGWOp (or sending a response in the case of non-mutating ops).
133 * The motivation driving the interface is to address those authentication
134 * schemas that require message integrity verification *without* in-memory
135 * data buffering. Typical examples are AWS Auth v4 and the auth mechanism
136 * of browser uploads facilities both in S3 and Swift APIs (see RGWPostObj).
137 * The workflow of request from the authentication point-of-view does look
138 * like following one:
139 * A. authenticate (Engine::authenticate),
140 * B. authorize (see RGWOp::verify_permissions),
141 * C. execute-prepare (init potential data modifications),
142 * D. authenticate-complete - (Completer::complete),
143 * E. execute-commit - commit the modifications from point C. */
146 /* It's expected that Completers would tend to implement many interfaces
147 * and be used not only in req_state::auth::completer. Ref counting their
148 * instances would be helpful. */
149 typedef std::shared_ptr
<Completer
> cmplptr_t
;
151 virtual ~Completer() = default;
153 /* Complete the authentication process. Return boolean indicating whether
154 * the completion succeeded. On error throws rgw::auth::Exception storing
156 virtual bool complete() = 0;
158 /* Apply any changes to request state. The initial use case was injecting
159 * the AWSv4 filter over rgw::io::RestfulClient in req_state. */
160 virtual void modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* s
) = 0; /* in/out */
164 /* Interface class for authentication backends (auth engines) in RadosGW.
166 * An engine is supposed only to authenticate (not authorize!) requests
167 * basing on their req_state and - if access has been granted - provide
168 * an upper layer with:
169 * - rgw::auth::IdentityApplier to commit all changes to the request state as
170 * well as to the RADOS store (creating an account, synchronizing
171 * user-related information with external databases and so on).
172 * - rgw::auth::Completer (optionally) to finish the authentication
173 * of the request. Typical use case is verifying message integrity
174 * in AWS Auth v4 and browser uploads (RGWPostObj).
176 * Both of them are supposed to be wrapped in Engine::AuthResult.
178 * The authentication process consists of two steps:
179 * - Engine::authenticate() which should be called before *initiating*
180 * any modifications to RADOS store that are related to an operation
181 * a client wants to perform (RGWOp::execute).
182 * - Completer::complete() supposed to be called, if completer has been
183 * returned, after the authenticate() step but before *committing*
184 * those modifications or sending a response (RGWOp::complete).
186 * An engine outlives both Applier and Completer. It's intended to live
187 * since RadosGW's initialization and handle multiple requests till
190 * Auth engine MUST NOT make any changes to req_state nor RADOS store.
191 * This is solely an Applier's responsibility!
193 * Separation between authentication and global state modification has
194 * been introduced because many auth engines are orthogonal to appliers
195 * and thus they can be decoupled. Additional motivation is to clearly
196 * distinguish all portions of code modifying data structures. */
199 virtual ~Engine() = default;
202 struct rejection_mark_t
{};
203 bool is_rejected
= false;
206 std::pair
<IdentityApplier::aplptr_t
, Completer::cmplptr_t
> result_pair
;
208 explicit AuthResult(const int reason
)
212 AuthResult(rejection_mark_t
&&, const int reason
)
217 /* Allow only the reasonable combintations - returning just Completer
218 * without accompanying IdentityApplier is strictly prohibited! */
219 explicit AuthResult(IdentityApplier::aplptr_t
&& applier
)
220 : result_pair(std::move(applier
), nullptr) {
223 AuthResult(IdentityApplier::aplptr_t
&& applier
,
224 Completer::cmplptr_t
&& completer
)
225 : result_pair(std::move(applier
), std::move(completer
)) {
230 /* Engine doesn't grant the access but also doesn't reject it. */
233 /* Engine successfully authenicated requester. */
236 /* Engine strictly indicates that a request should be rejected
237 * without trying any further engine. */
241 Status
get_status() const {
243 return Status::REJECTED
;
244 } else if (! result_pair
.first
) {
245 return Status::DENIED
;
247 return Status::GRANTED
;
251 int get_reason() const {
255 IdentityApplier::aplptr_t
get_applier() {
256 return std::move(result_pair
.first
);
259 Completer::cmplptr_t
&& get_completer() {
260 return std::move(result_pair
.second
);
263 static AuthResult
reject(const int reason
= -EACCES
) {
264 return AuthResult(rejection_mark_t(), reason
);
267 static AuthResult
deny(const int reason
= -EACCES
) {
268 return AuthResult(reason
);
271 static AuthResult
grant(IdentityApplier::aplptr_t
&& applier
) {
272 return AuthResult(std::move(applier
));
275 static AuthResult
grant(IdentityApplier::aplptr_t
&& applier
,
276 Completer::cmplptr_t
&& completer
) {
277 return AuthResult(std::move(applier
), std::move(completer
));
281 using result_t
= AuthResult
;
283 /* Get name of the auth engine. */
284 virtual const char* get_name() const noexcept
= 0;
286 /* Throwing method for identity verification. When the check is positive
287 * an implementation should return Engine::result_t containing:
288 * - a non-null pointer to an object conforming the Applier interface.
289 * Otherwise, the authentication is treated as failed.
290 * - a (potentially null) pointer to an object conforming the Completer
293 * On error throws rgw::auth::Exception containing the reason. */
294 virtual result_t
authenticate(const DoutPrefixProvider
* dpp
, const req_state
* s
) const = 0;
298 /* Interface for extracting a token basing from data carried by req_state. */
299 class TokenExtractor
{
301 virtual ~TokenExtractor() = default;
302 virtual std::string
get_token(const req_state
* s
) const = 0;
306 /* Abstract class for stacking sub-engines to expose them as a single
307 * Engine. It is responsible for ordering its sub-engines and managing
308 * fall-backs between them. Derivatee is supposed to encapsulate engine
309 * instances and add them using the add_engine() method in the order it
310 * wants to be tried during the call to authenticate().
312 * Each new Strategy should be exposed to StrategyRegistry for handling
313 * the dynamic reconfiguration. */
314 class Strategy
: public Engine
{
316 /* Specifiers controlling what happens when an associated engine fails.
317 * The names and semantic has been borrowed mostly from libpam. */
319 /* Failure of an engine injected with the REQUISITE specifier aborts
320 * the strategy's authentication process immediately. No other engine
324 /* Success of an engine injected with the SUFFICIENT specifier ends
325 * strategy's authentication process successfully. However, denying
326 * doesn't abort it -- there will be fall-back to following engine
327 * if the one that failed wasn't the last one. */
330 /* Like SUFFICIENT with the exception that on failure the reason code
331 * is not overridden. Instead, it's taken directly from the last tried
332 * non-FALLBACK engine. If there was no previous non-FALLBACK engine
333 * in a Strategy, then the result_t::deny(reason = -EACCES) is used. */
337 Engine::result_t
authenticate(const DoutPrefixProvider
* dpp
, const req_state
* s
) const override final
;
339 bool is_empty() const {
340 return auth_stack
.empty();
343 static int apply(const DoutPrefixProvider
* dpp
, const Strategy
& auth_strategy
, req_state
* s
) noexcept
;
346 /* Using the reference wrapper here to explicitly point out we are not
347 * interested in storing nulls while preserving the dynamic polymorphism. */
348 using stack_item_t
= std::pair
<std::reference_wrapper
<const Engine
>,
350 std::vector
<stack_item_t
> auth_stack
;
353 void add_engine(Control ctrl_flag
, const Engine
& engine
) noexcept
;
357 /* A class aggregating the knowledge about all Strategies in RadosGW. It is
358 * responsible for handling the dynamic reconfiguration on e.g. realm update.
359 * The definition is in rgw/rgw_auth_registry.h,
361 * Each new Strategy should be exposed to it. */
362 class StrategyRegistry
;
364 class WebIdentityApplier
: public IdentityApplier
{
366 CephContext
* const cct
;
369 rgw::web_idp::WebTokenClaims token_claims
;
371 string
get_idp_url() const;
374 WebIdentityApplier( CephContext
* const cct
,
376 const string
& role_session
,
377 const rgw::web_idp::WebTokenClaims
& token_claims
)
380 role_session(role_session
),
381 token_claims(token_claims
) {
384 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
{
385 user_info
.user_id
= rgw_user(token_claims
.sub
);
386 user_info
.display_name
= token_claims
.user_name
;
389 void modify_request_state(const DoutPrefixProvider
*dpp
, req_state
* s
) const override
;
391 uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const override
{
392 return RGW_PERM_NONE
;
395 bool is_admin_of(const rgw_user
& uid
) const override
{
399 bool is_owner_of(const rgw_user
& uid
) const override
{
403 uint32_t get_perm_mask() const override
{
404 return RGW_PERM_NONE
;
407 void to_str(std::ostream
& out
) const override
;
409 bool is_identity(const idset_t
& ids
) const override
;
411 uint32_t get_identity_type() const override
{
415 string
get_acct_name() const override
{
416 return token_claims
.user_name
;
419 string
get_subuser() const override
{
424 virtual ~Factory() {}
426 virtual aplptr_t
create_apl_web_identity( CephContext
* cct
,
428 const string
& role_session
,
429 const rgw::web_idp::WebTokenClaims
& token
) const = 0;
433 class ImplicitTenants
: public md_config_obs_t
{
435 enum implicit_tenant_flag_bits
{IMPLICIT_TENANTS_SWIFT
=1,
436 IMPLICIT_TENANTS_S3
=2, IMPLICIT_TENANTS_BAD
= -1, };
439 void recompute_value(const ConfigProxy
& );
440 class ImplicitTenantValue
{
441 friend class ImplicitTenants
;
443 ImplicitTenantValue(int v
) : v(v
) {};
445 bool inline is_split_mode()
447 assert(v
!= IMPLICIT_TENANTS_BAD
);
448 return v
== IMPLICIT_TENANTS_SWIFT
|| v
== IMPLICIT_TENANTS_S3
;
450 bool inline implicit_tenants_for_(const implicit_tenant_flag_bits bit
)
452 assert(v
!= IMPLICIT_TENANTS_BAD
);
453 return static_cast<bool>(v
&bit
);
457 ImplicitTenants(const ConfigProxy
& c
) { recompute_value(c
);}
458 ImplicitTenantValue
get_value() {
459 return ImplicitTenantValue(saved
);
462 const char** get_tracked_conf_keys() const override
;
463 void handle_conf_change(const ConfigProxy
& conf
,
464 const std::set
<std::string
> &changed
) override
;
467 std::tuple
<bool,bool> implicit_tenants_enabled_for_swift(CephContext
* const cct
);
468 std::tuple
<bool,bool> implicit_tenants_enabled_for_s3(CephContext
* const cct
);
470 /* rgw::auth::RemoteApplier targets those authentication engines which don't
471 * need to ask the RADOS store while performing the auth process. Instead,
472 * they obtain credentials from an external source like Keystone or LDAP.
474 * As the authenticated user may not have an account yet, RGWRemoteAuthApplier
475 * must be able to create it basing on data passed by an auth engine. Those
476 * data will be used to fill RGWUserInfo structure. */
477 class RemoteApplier
: public IdentityApplier
{
480 friend class RemoteApplier
;
482 const rgw_user acct_user
;
483 const std::string acct_name
;
484 const uint32_t perm_mask
;
486 const uint32_t acct_type
;
489 enum class acct_privilege_t
{
494 AuthInfo(const rgw_user
& acct_user
,
495 const std::string
& acct_name
,
496 const uint32_t perm_mask
,
497 const acct_privilege_t level
,
498 const uint32_t acct_type
=TYPE_NONE
)
499 : acct_user(acct_user
),
500 acct_name(acct_name
),
501 perm_mask(perm_mask
),
502 is_admin(acct_privilege_t::IS_ADMIN_ACCT
== level
),
503 acct_type(acct_type
) {
507 using aclspec_t
= rgw::auth::Identity::aclspec_t
;
508 typedef std::function
<uint32_t(const aclspec_t
&)> acl_strategy_t
;
511 CephContext
* const cct
;
513 /* Read-write is intensional here due to RGWUserInfo creation process. */
516 /* Supplemental strategy for extracting permissions from ACLs. Its results
517 * will be combined (ORed) with a default strategy that is responsible for
518 * handling backward compatibility. */
519 const acl_strategy_t extra_acl_strategy
;
522 rgw::auth::ImplicitTenants
& implicit_tenant_context
;
523 const rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit
;
525 virtual void create_account(const DoutPrefixProvider
* dpp
,
526 const rgw_user
& acct_user
,
527 bool implicit_tenant
,
528 RGWUserInfo
& user_info
) const; /* out */
531 RemoteApplier(CephContext
* const cct
,
533 acl_strategy_t
&& extra_acl_strategy
,
534 const AuthInfo
& info
,
535 rgw::auth::ImplicitTenants
& implicit_tenant_context
,
536 rgw::auth::ImplicitTenants::implicit_tenant_flag_bits implicit_tenant_bit
)
539 extra_acl_strategy(std::move(extra_acl_strategy
)),
541 implicit_tenant_context(implicit_tenant_context
),
542 implicit_tenant_bit(implicit_tenant_bit
) {
545 uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const override
;
546 bool is_admin_of(const rgw_user
& uid
) const override
;
547 bool is_owner_of(const rgw_user
& uid
) const override
;
548 bool is_identity(const idset_t
& ids
) const override
;
550 uint32_t get_perm_mask() const override
{ return info
.perm_mask
; }
551 void to_str(std::ostream
& out
) const override
;
552 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
; /* out */
553 uint32_t get_identity_type() const override
{ return info
.acct_type
; }
554 string
get_acct_name() const override
{ return info
.acct_name
; }
555 string
get_subuser() const override
{ return {}; }
558 virtual ~Factory() {}
559 /* Providing r-value reference here is required intensionally. Callee is
560 * thus disallowed to handle std::function in a way that could inhibit
561 * the move behaviour (like forgetting about std::moving a l-value). */
562 virtual aplptr_t
create_apl_remote(CephContext
* cct
,
564 acl_strategy_t
&& extra_acl_strategy
,
565 const AuthInfo
&info
) const = 0;
570 /* rgw::auth::LocalApplier targets those auth engines that base on the data
571 * enclosed in the RGWUserInfo control structure. As a side effect of doing
572 * the authentication process, they must have it loaded. Leveraging this is
573 * a way to avoid unnecessary calls to underlying RADOS store. */
574 class LocalApplier
: public IdentityApplier
{
575 using aclspec_t
= rgw::auth::Identity::aclspec_t
;
578 const RGWUserInfo user_info
;
579 const std::string subuser
;
582 uint32_t get_perm_mask(const std::string
& subuser_name
,
583 const RGWUserInfo
&uinfo
) const;
586 static const std::string NO_SUBUSER
;
588 LocalApplier(CephContext
* const cct
,
589 const RGWUserInfo
& user_info
,
591 const boost::optional
<uint32_t>& perm_mask
)
592 : user_info(user_info
),
593 subuser(std::move(subuser
)) {
595 this->perm_mask
= perm_mask
.get();
597 this->perm_mask
= RGW_PERM_INVALID
;
602 uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const override
;
603 bool is_admin_of(const rgw_user
& uid
) const override
;
604 bool is_owner_of(const rgw_user
& uid
) const override
;
605 bool is_identity(const idset_t
& ids
) const override
;
606 uint32_t get_perm_mask() const override
{
607 if (this->perm_mask
== RGW_PERM_INVALID
) {
608 return get_perm_mask(subuser
, user_info
);
610 return this->perm_mask
;
613 void to_str(std::ostream
& out
) const override
;
614 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
; /* out */
615 uint32_t get_identity_type() const override
{ return TYPE_RGW
; }
616 string
get_acct_name() const override
{ return {}; }
617 string
get_subuser() const override
{ return subuser
; }
620 virtual ~Factory() {}
621 virtual aplptr_t
create_apl_local(CephContext
* cct
,
623 const RGWUserInfo
& user_info
,
624 const std::string
& subuser
,
625 const boost::optional
<uint32_t>& perm_mask
) const = 0;
629 class RoleApplier
: public IdentityApplier
{
635 vector
<string
> role_policies
;
638 const rgw_user user_id
;
640 string role_session_name
;
641 std::vector
<string
> token_claims
;
645 RoleApplier(CephContext
* const cct
,
647 const rgw_user
& user_id
,
648 const string
& token_policy
,
649 const string
& role_session_name
,
650 const std::vector
<string
>& token_claims
)
653 token_policy(token_policy
),
654 role_session_name(role_session_name
),
655 token_claims(token_claims
) {}
657 uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const override
{
660 bool is_admin_of(const rgw_user
& uid
) const override
{
663 bool is_owner_of(const rgw_user
& uid
) const override
{
666 bool is_identity(const idset_t
& ids
) const override
;
667 uint32_t get_perm_mask() const override
{
668 return RGW_PERM_NONE
;
670 void to_str(std::ostream
& out
) const override
;
671 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
; /* out */
672 uint32_t get_identity_type() const override
{ return TYPE_ROLE
; }
673 string
get_acct_name() const override
{ return {}; }
674 string
get_subuser() const override
{ return {}; }
675 void modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* s
) const override
;
678 virtual ~Factory() {}
679 virtual aplptr_t
create_apl_role( CephContext
* cct
,
681 const rgw::auth::RoleApplier::Role
& role_name
,
682 const rgw_user
& user_id
,
683 const std::string
& token_policy
,
684 const std::string
& role_session
,
685 const std::vector
<string
>& token_claims
) const = 0;
689 /* The anonymous abstract engine. */
690 class AnonymousEngine
: public Engine
{
691 CephContext
* const cct
;
692 const rgw::auth::LocalApplier::Factory
* const apl_factory
;
695 AnonymousEngine(CephContext
* const cct
,
696 const rgw::auth::LocalApplier::Factory
* const apl_factory
)
698 apl_factory(apl_factory
) {
701 const char* get_name() const noexcept override
{
702 return "rgw::auth::AnonymousEngine";
705 Engine::result_t
authenticate(const DoutPrefixProvider
* dpp
, const req_state
* s
) const override final
;
708 virtual bool is_applicable(const req_state
*) const noexcept
{
713 } /* namespace auth */
714 } /* namespace rgw */
717 uint32_t rgw_perms_from_aclspec_default_strategy(
719 const rgw::auth::Identity::aclspec_t
& aclspec
);
721 #endif /* CEPH_RGW_AUTH_H */