diff options
Diffstat (limited to 'src/rgw/rgw_rest_sts.h')
-rw-r--r-- | src/rgw/rgw_rest_sts.h | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/src/rgw/rgw_rest_sts.h b/src/rgw/rgw_rest_sts.h new file mode 100644 index 000000000..6bcad31db --- /dev/null +++ b/src/rgw/rgw_rest_sts.h @@ -0,0 +1,229 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#pragma once + +#include "rgw_auth.h" +#include "rgw_auth_filters.h" +#include "rgw_rest.h" +#include "rgw_sts.h" +#include "rgw_web_idp.h" +#include "jwt-cpp/jwt.h" +#include "rgw_oidc_provider.h" + +namespace rgw::auth::sts { + +class WebTokenEngine : public rgw::auth::Engine { + static constexpr std::string_view princTagsNamespace = "https://aws.amazon.com/tags"; + CephContext* const cct; + RGWCtl* const ctl; + + using result_t = rgw::auth::Engine::result_t; + using Pair = std::pair<std::string, std::string>; + using token_t = std::unordered_multimap<string, string>; + using principal_tags_t = std::set<Pair>; + + const rgw::auth::TokenExtractor* const extractor; + const rgw::auth::WebIdentityApplier::Factory* const apl_factory; + + bool is_applicable(const std::string& token) const noexcept; + + bool is_client_id_valid(vector<string>& client_ids, const string& client_id) const; + + bool is_cert_valid(const vector<string>& thumbprints, const string& cert) const; + + boost::optional<RGWOIDCProvider> get_provider(const DoutPrefixProvider *dpp, const string& role_arn, const string& iss) const; + + std::string get_role_tenant(const std::string& role_arn) const; + + std::string get_role_name(const string& role_arn) const; + + std::string get_cert_url(const std::string& iss, const DoutPrefixProvider *dpp,optional_yield y) const; + + std::tuple<boost::optional<WebTokenEngine::token_t>, boost::optional<WebTokenEngine::principal_tags_t>> + get_from_jwt(const DoutPrefixProvider* dpp, const std::string& token, const req_state* const s, optional_yield y) const; + + void validate_signature (const DoutPrefixProvider* dpp, const jwt::decoded_jwt& decoded, const string& algorithm, const string& iss, const vector<string>& thumbprints, optional_yield y) const; + + result_t authenticate(const DoutPrefixProvider* dpp, + const std::string& token, + const req_state* s, optional_yield y) const; + + template <typename T> + void recurse_and_insert(const string& key, const jwt::claim& c, T& t) const; + WebTokenEngine::token_t get_token_claims(const jwt::decoded_jwt& decoded) const; + +public: + WebTokenEngine(CephContext* const cct, + RGWCtl* const ctl, + const rgw::auth::TokenExtractor* const extractor, + const rgw::auth::WebIdentityApplier::Factory* const apl_factory) + : cct(cct), + ctl(ctl), + extractor(extractor), + apl_factory(apl_factory) { + } + + const char* get_name() const noexcept override { + return "rgw::auth::sts::WebTokenEngine"; + } + + result_t authenticate(const DoutPrefixProvider* dpp, const req_state* const s, optional_yield y) const override { + return authenticate(dpp, extractor->get_token(s), s, y); + } +}; /* class WebTokenEngine */ + +class DefaultStrategy : public rgw::auth::Strategy, + public rgw::auth::TokenExtractor, + public rgw::auth::WebIdentityApplier::Factory { + RGWCtl* const ctl; + ImplicitTenants& implicit_tenant_context; + + /* The engine. */ + const WebTokenEngine web_token_engine; + + using aplptr_t = rgw::auth::IdentityApplier::aplptr_t; + + /* The method implements TokenExtractor for Web Token in req_state. */ + std::string get_token(const req_state* const s) const override { + return s->info.args.get("WebIdentityToken"); + } + + aplptr_t create_apl_web_identity( CephContext* cct, + const req_state* s, + const std::string& role_session, + const std::string& role_tenant, + const std::unordered_multimap<std::string, std::string>& token, + boost::optional<std::multimap<std::string, std::string>> role_tags, + boost::optional<std::set<std::pair<std::string, std::string>>> principal_tags) const override { + auto apl = rgw::auth::add_sysreq(cct, ctl, s, + rgw::auth::WebIdentityApplier(cct, ctl, role_session, role_tenant, token, role_tags, principal_tags)); + return aplptr_t(new decltype(apl)(std::move(apl))); + } + +public: + DefaultStrategy(CephContext* const cct, + ImplicitTenants& implicit_tenant_context, + RGWCtl* const ctl) + : ctl(ctl), + implicit_tenant_context(implicit_tenant_context), + web_token_engine(cct, ctl, + static_cast<rgw::auth::TokenExtractor*>(this), + static_cast<rgw::auth::WebIdentityApplier::Factory*>(this)) { + /* When the constructor's body is being executed, all member engines + * should be initialized. Thus, we can safely add them. */ + using Control = rgw::auth::Strategy::Control; + add_engine(Control::SUFFICIENT, web_token_engine); + } + + const char* get_name() const noexcept override { + return "rgw::auth::sts::DefaultStrategy"; + } +}; + +} // namespace rgw::auth::sts + +class RGWREST_STS : public RGWRESTOp { +protected: + STS::STSService sts; +public: + RGWREST_STS() = default; + int verify_permission(optional_yield y) override; + void send_response() override; +}; + +class RGWSTSAssumeRoleWithWebIdentity : public RGWREST_STS { +protected: + string duration; + string providerId; + string policy; + string roleArn; + string roleSessionName; + string sub; + string aud; + string iss; +public: + RGWSTSAssumeRoleWithWebIdentity() = default; + void execute(optional_yield y) override; + int get_params(); + const char* name() const override { return "assume_role_web_identity"; } + RGWOpType get_type() override { return RGW_STS_ASSUME_ROLE_WEB_IDENTITY; } +}; + +class RGWSTSAssumeRole : public RGWREST_STS { +protected: + string duration; + string externalId; + string policy; + string roleArn; + string roleSessionName; + string serialNumber; + string tokenCode; +public: + RGWSTSAssumeRole() = default; + void execute(optional_yield y) override; + int get_params(); + const char* name() const override { return "assume_role"; } + RGWOpType get_type() override { return RGW_STS_ASSUME_ROLE; } +}; + +class RGWSTSGetSessionToken : public RGWREST_STS { +protected: + string duration; + string serialNumber; + string tokenCode; +public: + RGWSTSGetSessionToken() = default; + void execute(optional_yield y) override; + int verify_permission(optional_yield y) override; + int get_params(); + const char* name() const override { return "get_session_token"; } + RGWOpType get_type() override { return RGW_STS_GET_SESSION_TOKEN; } +}; + +class RGW_Auth_STS { +public: + static int authorize(const DoutPrefixProvider *dpp, + rgw::sal::RGWRadosStore *store, + const rgw::auth::StrategyRegistry& auth_registry, + struct req_state *s, optional_yield y); +}; + +class RGWHandler_REST_STS : public RGWHandler_REST { + const rgw::auth::StrategyRegistry& auth_registry; + const string& post_body; + RGWOp *op_post() override; + void rgw_sts_parse_input(); +public: + + static int init_from_header(struct req_state *s, int default_formatter, bool configurable_format); + + RGWHandler_REST_STS(const rgw::auth::StrategyRegistry& auth_registry, const string& post_body="") + : RGWHandler_REST(), + auth_registry(auth_registry), + post_body(post_body) {} + ~RGWHandler_REST_STS() override = default; + + int init(rgw::sal::RGWRadosStore *store, + struct req_state *s, + rgw::io::BasicClient *cio) override; + int authorize(const DoutPrefixProvider* dpp, optional_yield y) override; + int postauth_init(optional_yield y) override { return 0; } +}; + +class RGWRESTMgr_STS : public RGWRESTMgr { +public: + RGWRESTMgr_STS() = default; + ~RGWRESTMgr_STS() override = default; + + RGWRESTMgr *get_resource_mgr(struct req_state* const s, + const std::string& uri, + std::string* const out_uri) override { + return this; + } + + RGWHandler_REST* get_handler(rgw::sal::RGWRadosStore *store, + struct req_state*, + const rgw::auth::StrategyRegistry&, + const std::string&) override; +}; |