X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_auth.h;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_auth.h;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=168498d033316004a6615d3c04ba626405ab5480;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_auth.h b/src/ceph/src/rgw/rgw_auth.h deleted file mode 100644 index 168498d..0000000 --- a/src/ceph/src/rgw/rgw_auth.h +++ /dev/null @@ -1,516 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - - -#ifndef CEPH_RGW_AUTH_H -#define CEPH_RGW_AUTH_H - -#include -#include -#include -#include -#include - -#include "rgw_common.h" -#include "rgw_keystone.h" - -#define RGW_USER_ANON_ID "anonymous" - -namespace rgw { -namespace auth { - -using Exception = std::system_error; - - -/* Load information about identity that will be used by RGWOp to authorize - * any operation that comes from an authenticated user. */ -class Identity { -public: - typedef std::map aclspec_t; - using idset_t = boost::container::flat_set; - - virtual ~Identity() = default; - - /* Translate the ACL provided in @aclspec into concrete permission set that - * can be used during the authorization phase (RGWOp::verify_permission). - * On error throws rgw::auth::Exception storing the reason. - * - * NOTE: an implementation is responsible for giving the real semantic to - * the items in @aclspec. That is, their meaning may depend on particular - * applier that is being used. */ - virtual uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const = 0; - - /* Verify whether a given identity *can be treated as* an admin of rgw_user - * (account in Swift's terminology) specified in @uid. On error throws - * rgw::auth::Exception storing the reason. */ - virtual bool is_admin_of(const rgw_user& uid) const = 0; - - /* Verify whether a given identity *is* the owner of the rgw_user (account - * in the Swift's terminology) specified in @uid. On internal error throws - * rgw::auth::Exception storing the reason. */ - virtual bool is_owner_of(const rgw_user& uid) const = 0; - - /* Return the permission mask that is used to narrow down the set of - * operations allowed for a given identity. This method reflects the idea - * of subuser tied to RGWUserInfo. On error throws rgw::auth::Exception - * with the reason. */ - virtual uint32_t get_perm_mask() const = 0; - - virtual bool is_anonymous() const final { - /* If the identity owns the anonymous account (rgw_user), it's considered - * the anonymous identity. On error throws rgw::auth::Exception storing - * the reason. */ - return is_owner_of(rgw_user(RGW_USER_ANON_ID)); - } - - virtual void to_str(std::ostream& out) const = 0; - - /* Verify whether a given identity corresponds to an identity in the - provided set */ - virtual bool is_identity(const idset_t& ids) const = 0; -}; - -inline std::ostream& operator<<(std::ostream& out, - const rgw::auth::Identity& id) { - id.to_str(out); - return out; -} - - -std::unique_ptr transform_old_authinfo(const req_state* const s); - - -/* Interface for classes applying changes to request state/RADOS store - * imposed by a particular rgw::auth::Engine. - * - * In contrast to rgw::auth::Engine, implementations of this interface - * are allowed to handle req_state or RGWRados in the read-write manner. - * - * It's expected that most (if not all) of implementations will also - * conform to rgw::auth::Identity interface to provide authorization - * policy (ACLs, account's ownership and entitlement). */ -class IdentityApplier : public Identity { -public: - typedef std::unique_ptr aplptr_t; - - virtual ~IdentityApplier() {}; - - /* Fill provided RGWUserInfo with information about the account that - * RGWOp will operate on. Errors are handled solely through exceptions. - * - * XXX: be aware that the "account" term refers to rgw_user. The naming - * is legacy. */ - virtual void load_acct_info(RGWUserInfo& user_info) const = 0; /* out */ - - /* Apply any changes to request state. This method will be most useful for - * TempURL of Swift API. */ - virtual void modify_request_state(req_state* s) const {} /* in/out */ -}; - - -/* Interface class for completing the two-step authentication process. - * Completer provides the second step - the complete() method that should - * be called after Engine::authenticate() but before *committing* results - * of an RGWOp (or sending a response in the case of non-mutating ops). - * - * The motivation driving the interface is to address those authentication - * schemas that require message integrity verification *without* in-memory - * data buffering. Typical examples are AWS Auth v4 and the auth mechanism - * of browser uploads facilities both in S3 and Swift APIs (see RGWPostObj). - * The workflow of request from the authentication point-of-view does look - * like following one: - * A. authenticate (Engine::authenticate), - * B. authorize (see RGWOp::verify_permissions), - * C. execute-prepare (init potential data modifications), - * D. authenticate-complete - (Completer::complete), - * E. execute-commit - commit the modifications from point C. */ -class Completer { -public: - /* It's expected that Completers would tend to implement many interfaces - * and be used not only in req_state::auth::completer. Ref counting their - * instances woild be helpful. */ - typedef std::shared_ptr cmplptr_t; - - virtual ~Completer() = default; - - /* Complete the authentication process. Return boolean indicating whether - * the completion succeeded. On error throws rgw::auth::Exception storing - * the reason. */ - virtual bool complete() = 0; - - /* Apply any changes to request state. The initial use case was injecting - * the AWSv4 filter over rgw::io::RestfulClient in req_state. */ - virtual void modify_request_state(req_state* s) = 0; /* in/out */ -}; - - -/* Interface class for authentication backends (auth engines) in RadosGW. - * - * An engine is supposed only to authenticate (not authorize!) requests - * basing on their req_state and - if access has been granted - provide - * an upper layer with: - * - rgw::auth::IdentityApplier to commit all changes to the request state as - * well as to the RADOS store (creating an account, synchronizing - * user-related information with external databases and so on). - * - rgw::auth::Completer (optionally) to finish the authentication - * of the request. Typical use case is verifying message integrity - * in AWS Auth v4 and browser uploads (RGWPostObj). - * - * Both of them are supposed to be wrapped in Engine::AuthResult. - * - * The authentication process consists of two steps: - * - Engine::authenticate() which should be called before *initiating* - * any modifications to RADOS store that are related to an operation - * a client wants to perform (RGWOp::execute). - * - Completer::complete() supposed to be called, if completer has been - * returned, after the authenticate() step but before *committing* - * those modifications or sending a response (RGWOp::complete). - * - * An engine outlives both Applier and Completer. It's intended to live - * since RadosGW's initialization and handle multiple requests till - * a reconfiguration. - * - * Auth engine MUST NOT make any changes to req_state nor RADOS store. - * This is solely an Applier's responsibility! - * - * Separation between authentication and global state modification has - * been introduced because many auth engines are orthogonal to appliers - * and thus they can be decoupled. Additional motivation is to clearly - * distinguish all portions of code modifying data structures. */ -class Engine { -public: - virtual ~Engine() = default; - - class AuthResult { - struct rejection_mark_t {}; - bool is_rejected = false; - int reason = 0; - - std::pair result_pair; - - AuthResult(const int reason) - : reason(reason) { - } - - AuthResult(rejection_mark_t&&, const int reason) - : is_rejected(true), - reason(reason) { - } - - /* Allow only the reasonable combintations - returning just Completer - * without accompanying IdentityApplier is strictly prohibited! */ - AuthResult(IdentityApplier::aplptr_t&& applier) - : result_pair(std::move(applier), nullptr) { - } - - AuthResult(IdentityApplier::aplptr_t&& applier, - Completer::cmplptr_t&& completer) - : result_pair(std::move(applier), std::move(completer)) { - } - - public: - enum class Status { - /* Engine doesn't grant the access but also doesn't reject it. */ - DENIED, - - /* Engine successfully authenticated requester. */ - GRANTED, - - /* Engine strictly indicates that a request should be rejected - * without trying any further engine. */ - REJECTED - }; - - Status get_status() const { - if (is_rejected) { - return Status::REJECTED; - } else if (! result_pair.first) { - return Status::DENIED; - } else { - return Status::GRANTED; - } - } - - int get_reason() const { - return reason; - } - - IdentityApplier::aplptr_t get_applier() { - return std::move(result_pair.first); - } - - Completer::cmplptr_t&& get_completer() { - return std::move(result_pair.second); - } - - static AuthResult reject(const int reason = -EACCES) { - return AuthResult(rejection_mark_t(), reason); - } - - static AuthResult deny(const int reason = -EACCES) { - return AuthResult(reason); - } - - static AuthResult grant(IdentityApplier::aplptr_t&& applier) { - return AuthResult(std::move(applier)); - } - - static AuthResult grant(IdentityApplier::aplptr_t&& applier, - Completer::cmplptr_t&& completer) { - return AuthResult(std::move(applier), std::move(completer)); - } - }; - - using result_t = AuthResult; - - /* Get name of the auth engine. */ - virtual const char* get_name() const noexcept = 0; - - /* Throwing method for identity verification. When the check is positive - * an implementation should return Engine::result_t containing: - * - a non-null pointer to an object conforming the Applier interface. - * Otherwise, the authentication is treated as failed. - * - a (potentially null) pointer to an object conforming the Completer - * interface. - * - * On error throws rgw::auth::Exception containing the reason. */ - virtual result_t authenticate(const req_state* s) const = 0; -}; - - -/* Interface for extracting a token basing from data carried by req_state. */ -class TokenExtractor { -public: - virtual ~TokenExtractor() = default; - virtual std::string get_token(const req_state* s) const = 0; -}; - - -/* Abstract class for stacking sub-engines to expose them as a single - * Engine. It is responsible for ordering its sub-engines and managing - * fall-backs between them. Derivatee is supposed to encapsulate engine - * instances and add them using the add_engine() method in the order it - * wants to be tried during the call to authenticate(). - * - * Each new Strategy should be exposed to StrategyRegistry for handling - * the dynamic reconfiguration. */ -class Strategy : public Engine { -public: - /* Specifiers controlling what happens when an associated engine fails. - * The names and semantic has been borrowed mostly from libpam. */ - enum class Control { - /* Failure of an engine injected with the REQUISITE specifier aborts - * the strategy's authentication process immediately. No other engine - * will be tried. */ - REQUISITE, - - /* Success of an engine injected with the SUFFICIENT specifier ends - * strategy's authentication process successfully. However, denying - * doesn't abort it -- there will be fall-back to following engine - * if the one that failed wasn't the last one. */ - SUFFICIENT, - - /* Like SUFFICIENT with the exception that on failure the reason code - * is not overridden. Instead, it's taken directly from the last tried - * non-FALLBACK engine. If there was no previous non-FALLBACK engine - * in a Strategy, then the result_t::deny(reason = -EACCES) is used. */ - FALLBACK, - }; - - Engine::result_t authenticate(const req_state* s) const override final; - - bool is_empty() const { - return auth_stack.empty(); - } - - static int apply(const Strategy& auth_strategy, req_state* s) noexcept; - -private: - /* Using the reference wrapper here to explicitly point out we are not - * interested in storing nulls while preserving the dynamic polymorphism. */ - using stack_item_t = std::pair, - Control>; - std::vector auth_stack; - -protected: - void add_engine(Control ctrl_flag, const Engine& engine) noexcept; -}; - - -/* A class aggregating the knowledge about all Strategies in RadosGW. It is - * responsible for handling the dynamic reconfiguration on e.g. realm update. - * The definition is in rgw/rgw_auth_registry.h, - * - * Each new Strategy should be exposed to it. */ -class StrategyRegistry; - -/* rgw::auth::RemoteApplier targets those authentication engines which don't - * need to ask the RADOS store while performing the auth process. Instead, - * they obtain credentials from an external source like Keystone or LDAP. - * - * As the authenticated user may not have an account yet, RGWRemoteAuthApplier - * must be able to create it basing on data passed by an auth engine. Those - * data will be used to fill RGWUserInfo structure. */ -class RemoteApplier : public IdentityApplier { -public: - class AuthInfo { - friend class RemoteApplier; - protected: - const rgw_user acct_user; - const std::string acct_name; - const uint32_t perm_mask; - const bool is_admin; - const uint32_t acct_type; - - public: - enum class acct_privilege_t { - IS_ADMIN_ACCT, - IS_PLAIN_ACCT - }; - - AuthInfo(const rgw_user& acct_user, - const std::string& acct_name, - const uint32_t perm_mask, - const acct_privilege_t level, - const uint32_t acct_type=TYPE_NONE) - : acct_user(acct_user), - acct_name(acct_name), - perm_mask(perm_mask), - is_admin(acct_privilege_t::IS_ADMIN_ACCT == level), - acct_type(acct_type) { - } - }; - - using aclspec_t = rgw::auth::Identity::aclspec_t; - typedef std::function acl_strategy_t; - -protected: - CephContext* const cct; - - /* Read-write is intensional here due to RGWUserInfo creation process. */ - RGWRados* const store; - - /* Supplemental strategy for extracting permissions from ACLs. Its results - * will be combined (ORed) with a default strategy that is responsible for - * handling backward compatibility. */ - const acl_strategy_t extra_acl_strategy; - - const AuthInfo info; - const bool implicit_tenants; - - virtual void create_account(const rgw_user& acct_user, - RGWUserInfo& user_info) const; /* out */ - -public: - RemoteApplier(CephContext* const cct, - RGWRados* const store, - acl_strategy_t&& extra_acl_strategy, - const AuthInfo& info, - const bool implicit_tenants) - : cct(cct), - store(store), - extra_acl_strategy(std::move(extra_acl_strategy)), - info(info), - implicit_tenants(implicit_tenants) { - } - - uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override; - bool is_admin_of(const rgw_user& uid) const override; - bool is_owner_of(const rgw_user& uid) const override; - bool is_identity(const idset_t& ids) const override; - - uint32_t get_perm_mask() const override { return info.perm_mask; } - void to_str(std::ostream& out) const override; - void load_acct_info(RGWUserInfo& user_info) const override; /* out */ - - struct Factory { - virtual ~Factory() {} - /* Providing r-value reference here is required intensionally. Callee is - * thus disallowed to handle std::function in a way that could inhibit - * the move behaviour (like forgetting about std::moving a l-value). */ - virtual aplptr_t create_apl_remote(CephContext* cct, - const req_state* s, - acl_strategy_t&& extra_acl_strategy, - const AuthInfo info) const = 0; - }; -}; - - -/* rgw::auth::LocalApplier targets those auth engines that base on the data - * enclosed in the RGWUserInfo control structure. As a side effect of doing - * the authentication process, they must have it loaded. Leveraging this is - * a way to avoid unnecessary calls to underlying RADOS store. */ -class LocalApplier : public IdentityApplier { - using aclspec_t = rgw::auth::Identity::aclspec_t; - -protected: - const RGWUserInfo user_info; - const std::string subuser; - - uint32_t get_perm_mask(const std::string& subuser_name, - const RGWUserInfo &uinfo) const; - -public: - static const std::string NO_SUBUSER; - - LocalApplier(CephContext* const cct, - const RGWUserInfo& user_info, - std::string subuser) - : user_info(user_info), - subuser(std::move(subuser)) { - } - - - uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override; - bool is_admin_of(const rgw_user& uid) const override; - bool is_owner_of(const rgw_user& uid) const override; - bool is_identity(const idset_t& ids) const override; - uint32_t get_perm_mask() const override { - return get_perm_mask(subuser, user_info); - } - void to_str(std::ostream& out) const override; - void load_acct_info(RGWUserInfo& user_info) const override; /* out */ - - struct Factory { - virtual ~Factory() {} - virtual aplptr_t create_apl_local(CephContext* cct, - const req_state* s, - const RGWUserInfo& user_info, - const std::string& subuser) const = 0; - }; -}; - - -/* The anonymous abstract engine. */ -class AnonymousEngine : public Engine { - CephContext* const cct; - const rgw::auth::LocalApplier::Factory* const apl_factory; - -public: - AnonymousEngine(CephContext* const cct, - const rgw::auth::LocalApplier::Factory* const apl_factory) - : cct(cct), - apl_factory(apl_factory) { - } - - const char* get_name() const noexcept override { - return "rgw::auth::AnonymousEngine"; - } - - Engine::result_t authenticate(const req_state* s) const override final; - -protected: - virtual bool is_applicable(const req_state*) const noexcept { - return true; - } -}; - -} /* namespace auth */ -} /* namespace rgw */ - - -uint32_t rgw_perms_from_aclspec_default_strategy( - const rgw_user& uid, - const rgw::auth::Identity::aclspec_t& aclspec); - -#endif /* CEPH_RGW_AUTH_H */