From: Casey Bodley Date: Thu, 29 Feb 2024 15:56:21 +0000 (-0500) Subject: rgw/auth: auth engines pass optional account info into identities X-Git-Tag: v19.1.0~99^2~43 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=e3d065b2e4c854ee325471e929b1fcbb5d375e3f;p=ceph.git rgw/auth: auth engines pass optional account info into identities the auth identities need the RGWAccountInfo instead of just the account id so they can fill in the correct ACLOwner::display_name this also adds account ownership support to WebIdentityApplier for AssumeRoleWithWebIdentity Signed-off-by: Casey Bodley (cherry picked from commit 8e839ef4be0617b0b881c4ec476c31ec260c5157) --- diff --git a/src/rgw/driver/rados/rgw_data_sync.cc b/src/rgw/driver/rados/rgw_data_sync.cc index 4e6295cc48acb..77e676c81a018 100644 --- a/src/rgw/driver/rados/rgw_data_sync.cc +++ b/src/rgw/driver/rados/rgw_data_sync.cc @@ -2645,13 +2645,12 @@ class RGWUserPermHandler { return ret; } - info->identity = rgw::auth::transform_old_authinfo(sync_env->cct, uid, - info->user_info.display_name, - info->user_info.path, - info->user_info.account_id, - RGW_PERM_FULL_CONTROL, - false, /* system_request? */ - info->user_info.type); + auto result = rgw::auth::transform_old_authinfo( + sync_env->dpp, null_yield, sync_env->driver, info->user_info); + if (!result) { + return result.error(); + } + info->identity = std::move(result).value(); map uattrs; diff --git a/src/rgw/rgw_auth.cc b/src/rgw/rgw_auth.cc index 8b8cce881ce79..b01451f047e24 100644 --- a/src/rgw/rgw_auth.cc +++ b/src/rgw/rgw_auth.cc @@ -5,6 +5,7 @@ #include #include +#include "common/errno.h" #include "rgw_common.h" #include "rgw_auth.h" #include "rgw_quota.h" @@ -64,78 +65,60 @@ static bool match_principal(std::string_view path, } static bool match_owner(const rgw_owner& owner, const rgw_user& uid, - std::string_view account_id) + const std::optional& account) { return std::visit(fu2::overload( [&uid] (const rgw_user& u) { return u == uid; }, - [&account_id] (const rgw_account_id& a) { return a == account_id; } - ), owner); + [&account] (const rgw_account_id& a) { + return account && a == account->id; + }), owner); } -static bool match_account_or_tenant(const rgw_account_id& account_id, +static bool match_account_or_tenant(const std::optional& account, std::string_view tenant, std::string_view expected) { - if (!account_id.empty()) { - return account_id == expected; - } else { - return tenant == expected; - } + return (account && account->id == expected) + || (tenant == expected); } -std::unique_ptr -transform_old_authinfo(CephContext* const cct, - const rgw_user& auth_id, - const std::string& display_name, - const std::string& path, - const rgw_account_id& account_id, - const int perm_mask, - const bool is_admin, - const uint32_t type) +auto transform_old_authinfo(const RGWUserInfo& user, + std::optional account) + -> std::unique_ptr { /* This class is not intended for public use. Should be removed altogether * with this function after moving all our APIs to the new authentication * infrastructure. */ class DummyIdentityApplier : public rgw::auth::Identity { - CephContext* const cct; - /* For this particular case it's OK to use rgw_user structure to convey * the identity info as this was the policy for doing that before the * new auth. */ const rgw_user id; const std::string display_name; const std::string path; - const rgw_account_id account_id; - const int perm_mask; const bool is_admin; const uint32_t type; + const std::optional account; public: - DummyIdentityApplier(CephContext* const cct, - const rgw_user& auth_id, - const std::string display_name, - const std::string path, - const rgw_account_id& account_id, - const int perm_mask, - const bool is_admin, - const uint32_t type) - : cct(cct), - id(auth_id), - display_name(display_name), - path(path), - account_id(account_id), - perm_mask(perm_mask), - is_admin(is_admin), - type(type) { - } + DummyIdentityApplier(const RGWUserInfo& user, + std::optional account) + : id(user.user_id), + display_name(user.display_name), + path(user.path), + is_admin(user.admin), + type(user.type), + account(std::move(account)) + {} ACLOwner get_aclowner() const { ACLOwner owner; - if (!account_id.empty()) { - owner.id.emplace(account_id); + if (account) { + owner.id = account->id; + owner.display_name = account->name; } else { owner.id = id; + owner.display_name = display_name; } - owner.display_name = display_name; return owner; } @@ -148,19 +131,19 @@ transform_old_authinfo(CephContext* const cct, } bool is_owner_of(const rgw_owner& o) const override { - return match_owner(o, id, account_id); + return match_owner(o, id, account); } bool is_identity(const Principal& p) const override { if (p.is_wildcard()) { return true; } else if (p.is_account()) { - return match_account_or_tenant(account_id, id.tenant, + return match_account_or_tenant(account, id.tenant, p.get_account()); } else if (p.is_user()) { std::string_view no_subuser; // account users can match both account- and tenant-based arns - if (!account_id.empty() && p.get_account() == account_id) { + if (account && p.get_account() == account->id) { return match_principal(path, display_name, no_subuser, p.get_id()); } else { return p.get_account() == id.tenant @@ -171,7 +154,7 @@ transform_old_authinfo(CephContext* const cct, } uint32_t get_perm_mask() const override { - return perm_mask; + return RGW_PERM_FULL_CONTROL; } uint32_t get_identity_type() const override { @@ -191,30 +174,35 @@ transform_old_authinfo(CephContext* const cct, void to_str(std::ostream& out) const override { out << "RGWDummyIdentityApplier(auth_id=" << id - << ", perm_mask=" << perm_mask << ", is_admin=" << is_admin << ")"; } }; - return std::make_unique( - cct, auth_id, display_name, path, account_id, - perm_mask, is_admin, type); + return std::make_unique(user, std::move(account)); } -std::unique_ptr -transform_old_authinfo(const req_state* const s) +auto transform_old_authinfo(const DoutPrefixProvider* dpp, + optional_yield y, + rgw::sal::Driver* driver, + const RGWUserInfo& user) + -> tl::expected, int> { - const RGWUserInfo& info = s->user->get_info(); - return transform_old_authinfo(s->cct, - info.user_id, - info.display_name, - info.path, - info.account_id, - s->perm_mask, - /* System user has admin permissions by default - it's supposed to pass - * through any security check. */ - s->system_request, - info.type); + std::optional account; + if (!user.account_id.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int r = driver->load_account_by_id(dpp, y, user.account_id, + *account, attrs, objv); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << user.account_id << " for user " << user.user_id + << ": " << cpp_strerror(r) << dendl; + return tl::unexpected(r); + } + } + + return transform_old_authinfo(user, std::move(account)); } } /* namespace auth */ @@ -454,10 +442,29 @@ rgw::auth::Strategy::add_engine(const Control ctrl_flag, auth_stack.push_back(std::make_pair(std::cref(engine), ctrl_flag)); } +ACLOwner rgw::auth::WebIdentityApplier::get_aclowner() const +{ + ACLOwner owner; + if (account) { + owner.id = account->id; + owner.display_name = account->name; + } else { + owner.id = rgw_user{role_tenant, sub, "oidc"}; + owner.display_name = user_name; + } + return owner; +} + +bool rgw::auth::WebIdentityApplier::is_owner_of(const rgw_owner& o) const +{ + return match_owner(o, rgw_user{role_tenant, sub, "oidc"}, account); +} + void rgw::auth::WebIdentityApplier::to_str(std::ostream& out) const { out << "rgw::auth::WebIdentityApplier(sub =" << sub << ", user_name=" << user_name + << ", role_id=" << role_id << ", provider_id =" << iss << ")"; } @@ -619,6 +626,7 @@ const std::string rgw::auth::RemoteApplier::AuthInfo::NO_ACCESS_KEY; ACLOwner rgw::auth::RemoteApplier::get_aclowner() const { ACLOwner owner; + // TODO: handle account ownership owner.id = info.acct_user; owner.display_name = info.acct_name; return owner; @@ -843,12 +851,13 @@ const std::string rgw::auth::LocalApplier::NO_ACCESS_KEY; ACLOwner rgw::auth::LocalApplier::get_aclowner() const { ACLOwner owner; - if (!user_info.account_id.empty()) { - owner.id = user_info.account_id; + if (account) { + owner.id = account->id; + owner.display_name = account->name; } else { owner.id = user_info.user_id; + owner.display_name = user_info.display_name; } - owner.display_name = user_info.display_name; return owner; } @@ -858,12 +867,11 @@ uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const DoutPrefixProvide uint32_t mask = rgw_perms_from_aclspec_default_strategy( user_info.user_id.to_str(), aclspec, dpp); - if (!user_info.account_id.empty()) { + if (account) { // account users also match acl grants to the account id. in aws, grantees // ONLY refer to accounts. but we continue to match user grants to preserve // access when moving legacy users into new accounts - mask |= rgw_perms_from_aclspec_default_strategy( - user_info.account_id, aclspec, dpp); + mask |= rgw_perms_from_aclspec_default_strategy(account->id, aclspec, dpp); } return mask; @@ -876,20 +884,18 @@ bool rgw::auth::LocalApplier::is_admin_of(const rgw_owner& o) const bool rgw::auth::LocalApplier::is_owner_of(const rgw_owner& o) const { - return match_owner(o, user_info.user_id, user_info.account_id); + return match_owner(o, user_info.user_id, account); } bool rgw::auth::LocalApplier::is_identity(const Principal& p) const { if (p.is_wildcard()) { return true; } else if (p.is_account()) { - return match_account_or_tenant(user_info.account_id, - user_info.user_id.tenant, + return match_account_or_tenant(account, user_info.user_id.tenant, p.get_account()); } else if (p.is_user()) { // account users can match both account- and tenant-based arns - if (!user_info.account_id.empty() && - p.get_account() == user_info.account_id) { + if (account && p.get_account() == account->id) { return match_principal(user_info.path, user_info.display_name, subuser, p.get_id()); } else { @@ -943,18 +949,19 @@ void rgw::auth::LocalApplier::write_ops_log_entry(rgw_log_entry& entry) const ACLOwner rgw::auth::RoleApplier::get_aclowner() const { ACLOwner owner; - if (!role.account_id.empty()) { - owner.id = role.account_id; + if (role.account) { + owner.id = role.account->id; + owner.display_name = role.account->name; } else { owner.id = token_attrs.user_id; + owner.display_name = role.name; } - owner.display_name = role.name; return owner; } bool rgw::auth::RoleApplier::is_owner_of(const rgw_owner& o) const { - return match_owner(o, token_attrs.user_id, role.account_id); + return match_owner(o, token_attrs.user_id, role.account); } void rgw::auth::RoleApplier::to_str(std::ostream& out) const { @@ -977,12 +984,12 @@ bool rgw::auth::RoleApplier::is_identity(const Principal& p) const { if (p.is_wildcard()) { return true; } else if (p.is_account()) { - return match_account_or_tenant(role.account_id, role.tenant, + return match_account_or_tenant(role.account, role.tenant, p.get_account()); } else if (p.is_role()) { std::string_view no_subuser; // account roles can match both account- and tenant-based arns - return match_account_or_tenant(role.account_id, role.tenant, p.get_account()) + return match_account_or_tenant(role.account, role.tenant, p.get_account()) && match_principal(role.path, role.name, no_subuser, p.get_id()); } else if (p.is_assumed_role()) { string role_session = role.name + "/" + token_attrs.role_session_name; //role/role-session @@ -1010,7 +1017,7 @@ void rgw::auth::RoleApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUs void rgw::auth::RoleApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const { // non-account identity policy is restricted to the current tenant - const std::string* policy_tenant = role.account_id.empty() ? &role.tenant : nullptr; + const std::string* policy_tenant = role.account ? nullptr : &role.tenant; for (const auto& policy : role.inline_policies) { try { @@ -1079,7 +1086,7 @@ rgw::auth::AnonymousEngine::authenticate(const DoutPrefixProvider* dpp, const re rgw_get_anon_user(user_info); auto apl = \ - apl_factory->create_apl_local(cct, s, user_info, + apl_factory->create_apl_local(cct, s, user_info, std::nullopt, rgw::auth::LocalApplier::NO_SUBUSER, std::nullopt, rgw::auth::LocalApplier::NO_ACCESS_KEY); return result_t::grant(std::move(apl)); diff --git a/src/rgw/rgw_auth.h b/src/rgw/rgw_auth.h index 64e55d532f061..0e7eabe0c9fdd 100644 --- a/src/rgw/rgw_auth.h +++ b/src/rgw/rgw_auth.h @@ -10,6 +10,7 @@ #include #include +#include "include/expected.hpp" #include "include/function2.hpp" #include "rgw_common.h" @@ -97,16 +98,17 @@ inline std::ostream& operator<<(std::ostream& out, } -std::unique_ptr -transform_old_authinfo(CephContext* const cct, - const rgw_user& auth_id, - const std::string& display_name, - const std::string& path, - const rgw_account_id& account_id, - const int perm_mask, - const bool is_admin, - const uint32_t type); -std::unique_ptr transform_old_authinfo(const req_state* const s); +// Return an identity for the given user and account. +auto transform_old_authinfo(const RGWUserInfo& user, + std::optional account) + -> std::unique_ptr; + +// Return an identity for the given user, loading its account if necessary. +auto transform_old_authinfo(const DoutPrefixProvider* dpp, + optional_yield y, + rgw::sal::Driver* driver, + const RGWUserInfo& user) + -> tl::expected, int>; /* Interface for classes applying changes to request state/RADOS store @@ -382,11 +384,13 @@ class WebIdentityApplier : public IdentityApplier { protected: CephContext* const cct; rgw::sal::Driver* driver; + std::string role_id; std::string role_session; std::string role_tenant; std::unordered_multimap token_claims; boost::optional> role_tags; boost::optional>> principal_tags; + std::optional account; std::string get_idp_url() const; @@ -397,18 +401,23 @@ protected: public: WebIdentityApplier( CephContext* const cct, rgw::sal::Driver* driver, + const std::string& role_id, const std::string& role_session, const std::string& role_tenant, const std::unordered_multimap& token_claims, boost::optional> role_tags, - boost::optional>> principal_tags) + boost::optional>> principal_tags, + std::optional account) : cct(cct), driver(driver), + role_id(role_id), role_session(role_session), role_tenant(role_tenant), token_claims(token_claims), role_tags(role_tags), - principal_tags(principal_tags) { + principal_tags(principal_tags), + account(std::move(account)) + { const auto& sub = token_claims.find("sub"); if(sub != token_claims.end()) { this->sub = sub->second; @@ -447,12 +456,7 @@ public: void modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const override; - ACLOwner get_aclowner() const override { - ACLOwner owner; - owner.id = rgw_user{role_tenant, sub, "oidc"}; - owner.display_name = user_name; - return owner; - } + ACLOwner get_aclowner() const override; uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override { return RGW_PERM_NONE; @@ -462,10 +466,7 @@ public: return false; } - bool is_owner_of(const rgw_owner& o) const override { - auto* uid = std::get_if(&o); - return uid && uid->id == sub && uid->tenant == role_tenant && uid->ns == "oidc"; - } + bool is_owner_of(const rgw_owner& o) const override; uint32_t get_perm_mask() const override { return RGW_PERM_NONE; @@ -497,11 +498,13 @@ public: virtual aplptr_t create_apl_web_identity( CephContext* cct, const req_state* s, + const std::string& role_id, const std::string& role_session, const std::string& role_tenant, const std::unordered_multimap& token, boost::optional>, - boost::optional>> principal_tags) const = 0; + boost::optional>> principal_tags, + std::optional account) const = 0; }; }; @@ -665,6 +668,7 @@ class LocalApplier : public IdentityApplier { protected: const RGWUserInfo user_info; + const std::optional account; const std::string subuser; uint32_t perm_mask; const std::string access_key_id; @@ -678,10 +682,12 @@ public: LocalApplier(CephContext* const cct, const RGWUserInfo& user_info, + std::optional account, std::string subuser, const std::optional& perm_mask, const std::string access_key_id) : user_info(user_info), + account(std::move(account)), subuser(std::move(subuser)), perm_mask(perm_mask.value_or(RGW_PERM_INVALID)), access_key_id(access_key_id) { @@ -715,6 +721,7 @@ public: virtual aplptr_t create_apl_local(CephContext* cct, const req_state* s, const RGWUserInfo& user_info, + std::optional account, const std::string& subuser, const std::optional& perm_mask, const std::string& access_key_id) const = 0; @@ -728,7 +735,7 @@ public: std::string name; std::string path; std::string tenant; - rgw_account_id account_id; + std::optional account; std::vector inline_policies; std::vector managed_policies; }; @@ -775,11 +782,11 @@ public: struct Factory { virtual ~Factory() {} - virtual aplptr_t create_apl_role( CephContext* cct, - const req_state* s, - const rgw::auth::RoleApplier::Role& role, - const rgw::auth::RoleApplier::TokenAttrs& token_attrs) const = 0; - }; + virtual aplptr_t create_apl_role(CephContext* cct, + const req_state* s, + Role role, + TokenAttrs token_attrs) const = 0; + }; }; /* The anonymous abstract engine. */ diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index b2b1238f31301..c7cde7c04969d 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -56,20 +56,22 @@ class STSAuthStrategy : public rgw::auth::Strategy, aplptr_t create_apl_local(CephContext* const cct, const req_state* const s, const RGWUserInfo& user_info, + std::optional account, const std::string& subuser, const std::optional& perm_mask, const std::string& access_key_id) const override { auto apl = rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask, access_key_id)); + rgw::auth::LocalApplier(cct, user_info, std::move(account), + subuser, perm_mask, access_key_id)); return aplptr_t(new decltype(apl)(std::move(apl))); } aplptr_t create_apl_role(CephContext* const cct, const req_state* const s, - const rgw::auth::RoleApplier::Role& role, - const rgw::auth::RoleApplier::TokenAttrs& token_attrs) const override { + RoleApplier::Role role, + RoleApplier::TokenAttrs token_attrs) const override { auto apl = rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::RoleApplier(cct, role, token_attrs)); + rgw::auth::RoleApplier(cct, std::move(role), std::move(token_attrs))); return aplptr_t(new decltype(apl)(std::move(apl))); } @@ -113,8 +115,8 @@ class ExternalAuthStrategy : public rgw::auth::Strategy, rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg, const rgw::auth::RemoteApplier::AuthInfo &info) const override { auto apl = rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::RemoteApplier(cct, driver, std::move(acl_alg), info, - implicit_tenant_context, + rgw::auth::RemoteApplier(cct, driver, std::move(acl_alg), + info, implicit_tenant_context, rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3)); /* TODO(rzarzynski): replace with static_ptr. */ return aplptr_t(new decltype(apl)(std::move(apl))); @@ -174,11 +176,13 @@ class AWSAuthStrategy : public rgw::auth::Strategy, aplptr_t create_apl_local(CephContext* const cct, const req_state* const s, const RGWUserInfo& user_info, + std::optional account, const std::string& subuser, const std::optional& perm_mask, const std::string& access_key_id) const override { auto apl = rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask, access_key_id)); + rgw::auth::LocalApplier(cct, user_info, std::move(account), + subuser, perm_mask, access_key_id)); /* TODO(rzarzynski): replace with static_ptr. */ return aplptr_t(new decltype(apl)(std::move(apl))); } diff --git a/src/rgw/rgw_lib.cc b/src/rgw/rgw_lib.cc index 5a8fc14a80471..85763e1a2671c 100644 --- a/src/rgw/rgw_lib.cc +++ b/src/rgw/rgw_lib.cc @@ -247,7 +247,8 @@ namespace rgw { /* FIXME: remove this after switching all handlers to the new * authentication infrastructure. */ if (! s->auth.identity) { - s->auth.identity = rgw::auth::transform_old_authinfo(s); + s->auth.identity = rgw::auth::transform_old_authinfo( + io->get_user(), std::nullopt); } ldpp_dout(s, 2) << "reading op permissions" << dendl; @@ -377,7 +378,8 @@ namespace rgw { /* FIXME: remove this after switching all handlers to the new authentication * infrastructure. */ if (! s->auth.identity) { - s->auth.identity = rgw::auth::transform_old_authinfo(s); + s->auth.identity = rgw::auth::transform_old_authinfo( + io_ctx.get_user(), std::nullopt); } ldpp_dout(s, 2) << "reading op permissions" << dendl; @@ -563,9 +565,10 @@ namespace rgw { if (ret < 0) { derr << "ERROR: failed reading user info: uid=" << uid << " ret=" << ret << dendl; + return ret; } user_info = user->get_info(); - return ret; + return 0; } int RGWLibRequest::read_permissions(RGWOp* op, optional_yield y) { diff --git a/src/rgw/rgw_lib.h b/src/rgw/rgw_lib.h index 30234eebcdd33..643e0c2c2d24c 100644 --- a/src/rgw/rgw_lib.h +++ b/src/rgw/rgw_lib.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include "rgw_common.h" #include "rgw_client_io.h" #include "rgw_rest.h" diff --git a/src/rgw/rgw_process.cc b/src/rgw/rgw_process.cc index 1765e83d62244..7a7f70fa30d84 100644 --- a/src/rgw/rgw_process.cc +++ b/src/rgw/rgw_process.cc @@ -366,7 +366,13 @@ int process_request(const RGWProcessEnv& penv, /* FIXME: remove this after switching all handlers to the new authentication * infrastructure. */ if (nullptr == s->auth.identity) { - s->auth.identity = rgw::auth::transform_old_authinfo(s); + auto result = rgw::auth::transform_old_authinfo( + op, yield, driver, s->user->get_info()); + if (!result) { + abort_early(s, op, result.error(), handler, yield); + goto done; + } + s->auth.identity = std::move(result).value(); } ldpp_dout(op, 2) << "normalizing buckets and tenants" << dendl; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 073b9bf9013f8..391953219ae57 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -6280,6 +6280,21 @@ rgw::auth::s3::LocalEngine::authenticate( } }*/ + std::optional account; + if (!user->get_info().account_id.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int r = driver->load_account_by_id(dpp, y, user->get_info().account_id, + *account, attrs, objv); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << user->get_info().account_id << " for user " << *user + << ": " << cpp_strerror(r) << dendl; + return result_t::deny(-EPERM); + } + } + const auto iter = user->get_info().access_keys.find(access_key_id); if (iter == std::end(user->get_info().access_keys)) { ldpp_dout(dpp, 0) << "ERROR: access key not encoded in user info" << dendl; @@ -6289,7 +6304,7 @@ rgw::auth::s3::LocalEngine::authenticate( /* Ignore signature for HTTP OPTIONS */ if (s->op_type == RGW_OP_OPTIONS_CORS) { - auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), + auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), std::move(account), k.subuser, std::nullopt, access_key_id); return result_t::grant(std::move(apl), completer_factory(k.key)); } @@ -6309,7 +6324,7 @@ rgw::auth::s3::LocalEngine::authenticate( return result_t::reject(-ERR_SIGNATURE_NO_MATCH); } - auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), + auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), std::move(account), k.subuser, std::nullopt, access_key_id); return result_t::grant(std::move(apl), completer_factory(k.key)); } @@ -6444,7 +6459,6 @@ rgw::auth::s3::STSEngine::authenticate( } // Get all the authorization info - std::unique_ptr user; rgw_user user_id; string role_id; rgw::auth::RoleApplier::Role r; @@ -6458,7 +6472,21 @@ rgw::auth::s3::STSEngine::authenticate( r.name = role->get_name(); r.path = role->get_path(); r.tenant = role->get_tenant(); - r.account_id = role->get_account_id(); + + const auto& account_id = role->get_account_id(); + if (!account_id.empty()) { + r.account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int ret = driver->load_account_by_id(dpp, y, account_id, + *r.account, attrs, objv); + if (ret < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << account_id << " for role " << r.name + << ": " << cpp_strerror(ret) << dendl; + return result_t::deny(-EPERM); + } + } for (auto& [name, policy] : role->get_info().perm_policy_map) { r.inline_policies.push_back(std::move(policy)); @@ -6468,16 +6496,6 @@ rgw::auth::s3::STSEngine::authenticate( } } - user = driver->get_user(token.user); - if (! token.user.empty() && token.acct_type != TYPE_ROLE) { - // get user info - int ret = user->load_user(dpp, y); - if (ret < 0) { - ldpp_dout(dpp, 5) << "ERROR: failed reading user info: uid=" << token.user << dendl; - return result_t::reject(-EPERM); - } - } - if (token.acct_type == TYPE_KEYSTONE || token.acct_type == TYPE_LDAP) { auto apl = remote_apl_factory->create_apl_remote(cct, s, get_acl_strategy(), get_creds_info(token)); @@ -6489,11 +6507,41 @@ rgw::auth::s3::STSEngine::authenticate( t_attrs.token_claims = std::move(token.token_claims); t_attrs.token_issued_at = std::move(token.issued_at); t_attrs.principal_tags = std::move(token.principal_tags); - auto apl = role_apl_factory->create_apl_role(cct, s, r, t_attrs); + auto apl = role_apl_factory->create_apl_role(cct, s, std::move(r), + std::move(t_attrs)); return result_t::grant(std::move(apl), completer_factory(token.secret_access_key)); } else { // This is for all local users of type TYPE_RGW|ROOT|NONE + if (token.user.empty()) { + ldpp_dout(dpp, 5) << "ERROR: got session token with empty user id" << dendl; + return result_t::reject(-EPERM); + } + // load user info + auto user = driver->get_user(token.user); + int ret = user->load_user(dpp, y); + if (ret < 0) { + ldpp_dout(dpp, 5) << "ERROR: failed reading user info: uid=" << token.user << dendl; + return result_t::reject(-EPERM); + } + + std::optional account; + if (!user->get_info().account_id.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int r = driver->load_account_by_id(dpp, y, user->get_info().account_id, + *account, attrs, objv); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << user->get_info().account_id << " for user " << *user + << ": " << cpp_strerror(r) << dendl; + return result_t::deny(-EPERM); + } + } + string subuser; - auto apl = local_apl_factory->create_apl_local(cct, s, user->get_info(), subuser, token.perm_mask, std::string(_access_key_id)); + auto apl = local_apl_factory->create_apl_local(cct, s, user->get_info(), + std::move(account), subuser, + token.perm_mask, std::string(_access_key_id)); return result_t::grant(std::move(apl), completer_factory(token.secret_access_key)); } } diff --git a/src/rgw/rgw_rest_sts.cc b/src/rgw/rgw_rest_sts.cc index cbb1b7de1180d..b9c23aa159c26 100644 --- a/src/rgw/rgw_rest_sts.cc +++ b/src/rgw/rgw_rest_sts.cc @@ -502,8 +502,24 @@ WebTokenEngine::authenticate( const DoutPrefixProvider* dpp, ldpp_dout(dpp, 0) << "Role not found: name:" << role_name << " tenant: " << role_tenant << dendl; return result_t::deny(-EACCES); } + + std::optional account; + if (!role_account.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + ret = driver->load_account_by_id(dpp, y, role_account, + *account, attrs, objv); + if (ret < 0) { + ldpp_dout(dpp, 0) << "Role account " << role_account << " not found" << dendl; + return result_t::deny(-EACCES); + } + } + boost::optional> role_tags = role->get_tags(); - auto apl = apl_factory->create_apl_web_identity(cct, s, role_session, role->get_tenant(), *t, role_tags, princ_tags); + auto apl = apl_factory->create_apl_web_identity( + cct, s, role->get_id(), role_session, role_tenant, + *t, role_tags, princ_tags, std::move(account)); return result_t::grant(std::move(apl)); } return result_t::deny(-EACCES); diff --git a/src/rgw/rgw_rest_sts.h b/src/rgw/rgw_rest_sts.h index aa66972943995..432244009202f 100644 --- a/src/rgw/rgw_rest_sts.h +++ b/src/rgw/rgw_rest_sts.h @@ -101,13 +101,17 @@ class DefaultStrategy : public rgw::auth::Strategy, aplptr_t create_apl_web_identity( CephContext* cct, const req_state* s, + const std::string& role_id, const std::string& role_session, const std::string& role_tenant, const std::unordered_multimap& token, boost::optional> role_tags, - boost::optional>> principal_tags) const override { + boost::optional>> principal_tags, + std::optional account) const override { auto apl = rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::WebIdentityApplier(cct, driver, role_session, role_tenant, token, role_tags, principal_tags)); + rgw::auth::WebIdentityApplier(cct, driver, role_id, role_session, + role_tenant, token, role_tags, + principal_tags, std::move(account))); return aplptr_t(new decltype(apl)(std::move(apl))); } diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index fe366acf8563a..129726f0584f8 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -2138,7 +2138,8 @@ bool RGWFormPost::is_integral() try { get_owner_info(s, s->user->get_info()); - s->auth.identity = rgw::auth::transform_old_authinfo(s); + s->auth.identity = rgw::auth::transform_old_authinfo( + s->user->get_info(), std::nullopt); } catch (...) { ldpp_dout(this, 5) << "cannot get user_info of account's owner" << dendl; return false; diff --git a/src/rgw/rgw_swift_auth.cc b/src/rgw/rgw_swift_auth.cc index 9edf257b6b80b..f191d3628af99 100644 --- a/src/rgw/rgw_swift_auth.cc +++ b/src/rgw/rgw_swift_auth.cc @@ -513,7 +513,23 @@ ExternalTokenEngine::authenticate(const DoutPrefixProvider* dpp, throw ret; } + std::optional account; + if (!user->get_info().account_id.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int r = driver->load_account_by_id(dpp, y, user->get_info().account_id, + *account, attrs, objv); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << user->get_info().account_id << " for user " << *user + << ": " << cpp_strerror(r) << dendl; + return result_t::deny(-EPERM); + } + } + auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), + std::move(account), extract_swift_subuser(swift_user), std::nullopt, rgw::auth::LocalApplier::NO_ACCESS_KEY); return result_t::grant(std::move(apl)); @@ -633,6 +649,21 @@ SignedTokenEngine::authenticate(const DoutPrefixProvider* dpp, throw ret; } + std::optional account; + if (!user->get_info().account_id.empty()) { + account.emplace(); + rgw::sal::Attrs attrs; // ignored + RGWObjVersionTracker objv; // ignored + int r = driver->load_account_by_id(dpp, s->yield, user->get_info().account_id, + *account, attrs, objv); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to load account " + << user->get_info().account_id << " for user " << *user + << ": " << cpp_strerror(r) << dendl; + return result_t::deny(-EPERM); + } + } + ldpp_dout(dpp, 10) << "swift_user=" << swift_user << dendl; const auto siter = user->get_info().swift_keys.find(swift_user); @@ -668,6 +699,7 @@ SignedTokenEngine::authenticate(const DoutPrefixProvider* dpp, } auto apl = apl_factory->create_apl_local(cct, s, user->get_info(), + std::move(account), extract_swift_subuser(swift_user), std::nullopt, rgw::auth::LocalApplier::NO_ACCESS_KEY); return result_t::grant(std::move(apl)); diff --git a/src/rgw/rgw_swift_auth.h b/src/rgw/rgw_swift_auth.h index 1c72a9472f65f..c5435556fd2a7 100644 --- a/src/rgw/rgw_swift_auth.h +++ b/src/rgw/rgw_swift_auth.h @@ -24,8 +24,9 @@ class TempURLApplier : public rgw::auth::LocalApplier { public: TempURLApplier(CephContext* const cct, const RGWUserInfo& user_info) - : LocalApplier(cct, user_info, LocalApplier::NO_SUBUSER, std::nullopt, LocalApplier::NO_ACCESS_KEY) { - }; + : LocalApplier(cct, user_info, std::nullopt, LocalApplier::NO_SUBUSER, + std::nullopt, LocalApplier::NO_ACCESS_KEY) + {} void modify_request_state(const DoutPrefixProvider* dpp, req_state * s) const override; /* in/out */ void write_ops_log_entry(rgw_log_entry& entry) const override; @@ -155,7 +156,8 @@ class SwiftAnonymousApplier : public rgw::auth::LocalApplier { public: SwiftAnonymousApplier(CephContext* const cct, const RGWUserInfo& user_info) - : LocalApplier(cct, user_info, LocalApplier::NO_SUBUSER, std::nullopt, LocalApplier::NO_ACCESS_KEY) { + : LocalApplier(cct, user_info, std::nullopt, LocalApplier::NO_SUBUSER, + std::nullopt, LocalApplier::NO_ACCESS_KEY) { } bool is_admin_of(const rgw_owner& o) const {return false;} bool is_owner_of(const rgw_owner& o) const { @@ -237,13 +239,15 @@ class DefaultStrategy : public rgw::auth::Strategy, aplptr_t create_apl_local(CephContext* const cct, const req_state* const s, const RGWUserInfo& user_info, + std::optional account, const std::string& subuser, const std::optional& perm_mask, const std::string& access_key_id) const override { auto apl = \ rgw::auth::add_3rdparty(driver, rgw_user(s->account_name), rgw::auth::add_sysreq(cct, driver, s, - rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask, access_key_id))); + rgw::auth::LocalApplier(cct, user_info, std::move(account), + subuser, perm_mask, access_key_id))); /* TODO(rzarzynski): replace with static_ptr. */ return aplptr_t(new decltype(apl)(std::move(apl))); }