From: Casey Bodley Date: Mon, 19 Feb 2024 22:31:55 +0000 (-0500) Subject: rgw: forward_to_master() passes rgw_owner for effective uid header X-Git-Tag: v20.0.0~2159^2~57 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8d50f6103ff481a6ef4bf7c894e1d4329eefcf49;p=ceph.git rgw: forward_to_master() passes rgw_owner for effective uid header when s3 requests get forwarded to the master zone in multisite, we sign them as the multisite system user because we need to extend the s3 protocol. for example, CreateBucket requests issues by a system user include an extra response body that encodes the RGWBucketInfo. this way, the secondary zone can recreate exactly the same bucket that the master zone did these forwarded requests include a header like "rgwx-uid: myuserid" to request that the system user impersonate the given uid. this isn't necessary for authorization, because the system user overrides permission checks already. but it's important for resource ownership - the result of a forwarded CreateBucket request should be a bucket owned by "myuserid", not the system user because this "rgwx-uid" header is concerned with ownership, we pass the string encoding of rgw_owner instead of rgw_user. on the receiving side, we parse this header in SysReqApplier and override get_aclowner() to expose it Signed-off-by: Casey Bodley --- diff --git a/src/rgw/rgw_auth_filters.h b/src/rgw/rgw_auth_filters.h index b81bcefd13f4..3725b17514ed 100644 --- a/src/rgw/rgw_auth_filters.h +++ b/src/rgw/rgw_auth_filters.h @@ -3,10 +3,10 @@ #pragma once +#include #include #include -#include #include "rgw_service.h" #include "rgw_common.h" @@ -228,6 +228,7 @@ class SysReqApplier : public DecoratedApplier { rgw::sal::Driver* driver; const RGWHTTPArgs& args; mutable boost::tribool is_system; + mutable std::optional effective_owner; public: template @@ -245,12 +246,23 @@ public: void to_str(std::ostream& out) const override; void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override; /* out */ void modify_request_state(const DoutPrefixProvider* dpp, req_state* s) const override; /* in/out */ + + ACLOwner get_aclowner() const override { + if (effective_owner) { + return *effective_owner; + } + return DecoratedApplier::get_aclowner(); + } }; template void SysReqApplier::to_str(std::ostream& out) const { - out << "rgw::auth::SysReqApplier" << " -> "; + out << "rgw::auth::SysReqApplier"; + if (effective_owner) { + out << '(' << effective_owner->id << ')'; + } + out << " -> "; DecoratedApplier::to_str(out); } @@ -263,17 +275,19 @@ void SysReqApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo if (is_system) { //ldpp_dout(dpp, 20) << "system request" << dendl; - rgw_user effective_uid(args.sys_get(RGW_SYS_PARAM_PREFIX "uid")); - if (! effective_uid.empty()) { - /* We aren't writing directly to user_info for consistency and security - * reasons. rgw_get_user_info_by_uid doesn't trigger the operator=() but - * calls ::decode instead. */ - std::unique_ptr user = driver->get_user(effective_uid); - if (user->load_user(dpp, null_yield) < 0) { - //ldpp_dout(dpp, 0) << "User lookup failed!" << dendl; - throw -EACCES; + std::string str = args.sys_get(RGW_SYS_PARAM_PREFIX "uid"); + if (!str.empty()) { + effective_owner.emplace(); + effective_owner->id = parse_owner(str); + + if (const auto* uid = std::get_if(&effective_owner->id); uid) { + std::unique_ptr user = driver->get_user(*uid); + if (user->load_user(dpp, null_yield) < 0) { + //ldpp_dout(dpp, 0) << "User lookup failed!" << dendl; + throw -EACCES; + } + effective_owner->display_name = user->get_display_name(); } - user_info = user->get_info(); } } } diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 9991ec57e365..464bba7831b7 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -111,7 +111,7 @@ static constexpr auto S3_RUNTIME_RESOURCE_VAL = "${s3:ResourceTag"; int rgw_forward_request_to_master(const DoutPrefixProvider* dpp, const rgw::SiteConfig& site, - const rgw_user& uid, + const rgw_owner& effective_owner, bufferlist* indata, JSONParser* jp, req_info& req, optional_yield y) { @@ -144,8 +144,8 @@ int rgw_forward_request_to_master(const DoutPrefixProvider* dpp, creds, zg->second.id, zg->second.api_name}; bufferlist outdata; constexpr size_t max_response_size = 128 * 1024; // we expect a very small response - int ret = conn.forward(dpp, uid, req, nullptr, max_response_size, - indata, &outdata, y); + int ret = conn.forward(dpp, effective_owner, req, nullptr, + max_response_size, indata, &outdata, y); if (ret < 0) { return ret; } @@ -1298,7 +1298,7 @@ void RGWPutBucketTags::execute(optional_yield y) if (op_ret < 0) return; - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -1329,7 +1329,7 @@ int RGWDeleteBucketTags::verify_permission(optional_yield y) void RGWDeleteBucketTags::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -1385,7 +1385,7 @@ void RGWPutBucketReplication::execute(optional_yield y) { if (op_ret < 0) return; - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -1427,7 +1427,7 @@ int RGWDeleteBucketReplication::verify_permission(optional_yield y) void RGWDeleteBucketReplication::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -2902,7 +2902,7 @@ void RGWSetBucketVersioning::execute(optional_yield y) } } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -2992,7 +2992,7 @@ void RGWSetBucketWebsite::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << " forward_request_to_master returned ret=" << op_ret << dendl; @@ -3034,7 +3034,7 @@ void RGWDeleteBucketWebsite::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "NOTICE: forward_to_master failed on bucket=" << s->bucket->get_name() @@ -3677,7 +3677,7 @@ void RGWCreateBucket::execute(optional_yield y) // apply bucket creation on the master zone first bufferlist in_data; JSONParser jp; - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, &jp, s->info, y); if (op_ret < 0) { return; @@ -3822,7 +3822,7 @@ void RGWDeleteBucket::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { if (op_ret == -ENOENT) { @@ -6177,7 +6177,7 @@ void RGWPutACLs::execute(optional_yield y) // forward bucket acl requests to meta master zone if ((rgw::sal::Object::empty(s->object.get()))) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -6303,7 +6303,7 @@ void RGWPutLC::execute(optional_yield y) ldpp_dout(this, 15) << "New LifecycleConfiguration:" << ss.str() << dendl; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -6319,7 +6319,7 @@ void RGWPutLC::execute(optional_yield y) void RGWDeleteLC::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -6372,7 +6372,7 @@ void RGWPutCORS::execute(optional_yield y) if (op_ret < 0) return; - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -6398,7 +6398,7 @@ int RGWDeleteCORS::verify_permission(optional_yield y) void RGWDeleteCORS::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -6521,7 +6521,7 @@ void RGWSetRequestPayment::execute(optional_yield y) if (op_ret < 0) return; - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -7585,7 +7585,7 @@ bool RGWBulkDelete::Deleter::delete_single(const acct_path_t& path, optional_yie req_info req = s->info; forward_req_info(dpp, s->cct, req, path.bucket_name); - ret = rgw_forward_request_to_master(dpp, *s->penv.site, s->user->get_id(), + ret = rgw_forward_request_to_master(dpp, *s->penv.site, s->owner.id, nullptr, nullptr, req, y); if (ret < 0) { goto delop_fail; @@ -7841,7 +7841,7 @@ int RGWBulkUploadOp::handle_dir(const std::string_view path, optional_yield y) req_info req = s->info; forward_req_info(this, s->cct, req, bucket_name); - ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &in_data, &jp, req, y); if (ret < 0) { return ret; @@ -8551,7 +8551,7 @@ void RGWPutBucketPolicy::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 20) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -8653,7 +8653,7 @@ int RGWDeleteBucketPolicy::verify_permission(optional_yield y) void RGWDeleteBucketPolicy::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -8720,7 +8720,7 @@ void RGWPutBucketObjectLock::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 20) << __func__ << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -9083,7 +9083,7 @@ void RGWPutBucketPublicAccessBlock::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -9165,7 +9165,7 @@ int RGWDeleteBucketPublicAccessBlock::verify_permission(optional_yield y) void RGWDeleteBucketPublicAccessBlock::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -9221,7 +9221,7 @@ void RGWPutBucketEncryption::execute(optional_yield y) return; } - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, &data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 20) << "forward_request_to_master returned ret=" << op_ret << dendl; @@ -9276,7 +9276,7 @@ int RGWDeleteBucketEncryption::verify_permission(optional_yield y) void RGWDeleteBucketEncryption::execute(optional_yield y) { - op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id, nullptr, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index ac2f0ba98cba..016a6f38dd39 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -70,7 +70,7 @@ namespace rgw::auth::registry { class StrategyRegistry; } int rgw_forward_request_to_master(const DoutPrefixProvider* dpp, const rgw::SiteConfig& site, - const rgw_user& uid, + const rgw_owner& effective_owner, bufferlist* indata, JSONParser* jp, req_info& req, optional_yield y); diff --git a/src/rgw/rgw_rest_conn.cc b/src/rgw/rgw_rest_conn.cc index 2c1ff1a0a3f0..39d171dfb52f 100644 --- a/src/rgw/rgw_rest_conn.cc +++ b/src/rgw/rgw_rest_conn.cc @@ -147,13 +147,13 @@ void RGWRESTConn::set_url_unconnectable(const std::string& endpoint) ldout(cct, 10) << "set endpoint unconnectable. url=" << endpoint << dendl; } -void RGWRESTConn::populate_params(param_vec_t& params, const rgw_user *uid, const string& zonegroup) +void RGWRESTConn::populate_params(param_vec_t& params, const rgw_owner* uid, const string& zonegroup) { populate_uid(params, uid); populate_zonegroup(params, zonegroup); } -int RGWRESTConn::forward(const DoutPrefixProvider *dpp, const rgw_user& uid, const req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y) +int RGWRESTConn::forward(const DoutPrefixProvider *dpp, const rgw_owner& uid, const req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y) { int ret = 0; @@ -225,9 +225,8 @@ int RGWRESTConn::put_obj_send_init(const rgw_obj& obj, const rgw_http_param_pair if (ret < 0) return ret; - rgw_user uid; param_vec_t params; - populate_params(params, &uid, self_zone_group); + populate_params(params, nullptr, self_zone_group); if (extra_params) { append_param_list(params, extra_params); @@ -240,7 +239,7 @@ int RGWRESTConn::put_obj_send_init(const rgw_obj& obj, const rgw_http_param_pair return 0; } -int RGWRESTConn::put_obj_async_init(const DoutPrefixProvider *dpp, const rgw_user& uid, const rgw_obj& obj, +int RGWRESTConn::put_obj_async_init(const DoutPrefixProvider *dpp, const rgw_owner& uid, const rgw_obj& obj, map& attrs, RGWRESTStreamS3PutObj **req) { @@ -296,7 +295,7 @@ static void set_header(T val, map& headers, const string& header } -int RGWRESTConn::get_obj(const DoutPrefixProvider *dpp, const rgw_user& uid, req_info *info /* optional */, const rgw_obj& obj, +int RGWRESTConn::get_obj(const DoutPrefixProvider *dpp, const rgw_owner& uid, req_info *info /* optional */, const rgw_obj& obj, const real_time *mod_ptr, const real_time *unmod_ptr, uint32_t mod_zone_id, uint64_t mod_pg_ver, bool prepend_metadata, bool get_op, bool rgwx_stat, diff --git a/src/rgw/rgw_rest_conn.h b/src/rgw/rgw_rest_conn.h index 07ca83212cac..b2d1affb640f 100644 --- a/src/rgw/rgw_rest_conn.h +++ b/src/rgw/rgw_rest_conn.h @@ -127,10 +127,10 @@ public: } size_t get_endpoint_count() const { return endpoints.size(); } - virtual void populate_params(param_vec_t& params, const rgw_user *uid, const std::string& zonegroup); + virtual void populate_params(param_vec_t& params, const rgw_owner* uid, const std::string& zonegroup); /* sync request */ - int forward(const DoutPrefixProvider *dpp, const rgw_user& uid, const req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y); + int forward(const DoutPrefixProvider *dpp, const rgw_owner& uid, const req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y); /* sync request */ int forward_iam_request(const DoutPrefixProvider *dpp, const req_info& info, obj_version *objv, size_t max_response, bufferlist *inbl, bufferlist *outbl, optional_yield y); @@ -138,13 +138,13 @@ public: /* async requests */ int put_obj_send_init(const rgw_obj& obj, const rgw_http_param_pair *extra_params, RGWRESTStreamS3PutObj **req); - int put_obj_async_init(const DoutPrefixProvider *dpp, const rgw_user& uid, const rgw_obj& obj, + int put_obj_async_init(const DoutPrefixProvider *dpp, const rgw_owner& uid, const rgw_obj& obj, std::map& attrs, RGWRESTStreamS3PutObj **req); int complete_request(RGWRESTStreamS3PutObj *req, std::string& etag, ceph::real_time *mtime, optional_yield y); struct get_obj_params { - rgw_user uid; + rgw_owner uid; req_info *info{nullptr}; const ceph::real_time *mod_ptr{nullptr}; const ceph::real_time *unmod_ptr{nullptr}; @@ -172,7 +172,7 @@ public: int get_obj(const DoutPrefixProvider *dpp, const rgw_obj& obj, const get_obj_params& params, bool send, RGWRESTStreamRWRequest **req); - int get_obj(const DoutPrefixProvider *dpp, const rgw_user& uid, req_info *info /* optional */, const rgw_obj& obj, + int get_obj(const DoutPrefixProvider *dpp, const rgw_owner& uid, req_info *info /* optional */, const rgw_obj& obj, const ceph::real_time *mod_ptr, const ceph::real_time *unmod_ptr, uint32_t mod_zone_id, uint64_t mod_pg_ver, bool prepend_metadata, bool get_op, bool rgwx_stat, bool sync_manifest, @@ -221,12 +221,9 @@ private: params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "zonegroup", zonegroup)); } } - void populate_uid(param_vec_t& params, const rgw_user *uid) { + void populate_uid(param_vec_t& params, const rgw_owner* uid) { if (uid) { - std::string uid_str = uid->to_str(); - if (!uid->empty()){ - params.push_back(param_pair_t(RGW_SYS_PARAM_PREFIX "uid", uid_str)); - } + params.emplace_back(RGW_SYS_PARAM_PREFIX "uid", to_string(*uid)); } } }; @@ -241,7 +238,8 @@ public: RGWRESTConn(_cct, _remote_id, endpoints, _cred, _zone_group, _api_name, _host_style) {} ~S3RESTConn() override = default; - void populate_params(param_vec_t& params, const rgw_user *uid, const std::string& zonegroup) override { + void populate_params(param_vec_t& params, const rgw_owner* uid, + const std::string& zonegroup) override { // do not populate any params in S3 REST Connection. return; }