mirror of
https://github.com/ceph/ceph
synced 2025-01-02 00:52:22 +00:00
rgw: introduce and document new interfaces to the auth subsystem.
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
This commit is contained in:
parent
9804468266
commit
b560d98431
@ -8,6 +8,8 @@
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
#include "rgw_common.h"
|
||||
#include "rgw_keystone.h"
|
||||
@ -348,4 +350,173 @@ public:
|
||||
RGWAuthApplier::aplptr_t authenticate() const override;
|
||||
};
|
||||
|
||||
|
||||
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<std::string, int> aclspec_t;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const rgw::auth::Identity& id) {
|
||||
id.to_str(out);
|
||||
return 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 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).
|
||||
*
|
||||
* The authentication process consists two steps:
|
||||
* - Engine::authenticate() supposed to 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;
|
||||
|
||||
using result_t = std::pair<std::unique_ptr<class IdentityApplier>,
|
||||
std::unique_ptr<class Completer>>;
|
||||
|
||||
/* 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 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:
|
||||
typedef std::unique_ptr<Completer> 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;
|
||||
};
|
||||
|
||||
|
||||
/* 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(). */
|
||||
class Strategy : public Engine {
|
||||
public:
|
||||
/* Specifiers controlling what happens when an associated engine fails.
|
||||
* The names and semantic has been borrowed from libpam. */
|
||||
enum class Control {
|
||||
/* Failure of an engine injected with the REQUISITE specifier aborts
|
||||
* the whole authentication process immediately. No other engine will
|
||||
* be tried. */
|
||||
REQUISITE,
|
||||
|
||||
/* Success of an engine injected with the SUFFICIENT specifier ends
|
||||
* the whole authentication process successfully. However, failure
|
||||
* doesn't abort it - there will be fall-back to following engine
|
||||
* it the one that failed wasn't the last. */
|
||||
SUFFICIENT,
|
||||
};
|
||||
|
||||
Engine::result_t authenticate(const req_state* s) const override final;
|
||||
|
||||
protected:
|
||||
void add_engine(Control ctrl_flag, const Engine& engine) noexcept;
|
||||
};
|
||||
|
||||
} /* namespace auth */
|
||||
} /* namespace rgw */
|
||||
|
||||
#endif /* CEPH_RGW_AUTH_H */
|
||||
|
Loading…
Reference in New Issue
Block a user