From 1bc51e2fc80db68b2630b9fa9d5a77da7529b668 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 22 Nov 2019 15:31:55 -0800 Subject: [PATCH] rgw: api to check bucket and object permissions without need for req_state Signed-off-by: Yehuda Sadeh --- src/rgw/rgw_common.cc | 174 ++++++++++++++++++++++++++++++------------ src/rgw/rgw_common.h | 69 +++++++++++++++++ 2 files changed, 196 insertions(+), 47 deletions(-) diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index 327f4f91116..34063bfff68 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -994,7 +994,39 @@ bool rgw_transport_is_secure(CephContext *cct, const RGWEnv& env) return false; } + namespace { + +struct perm_state_from_req_state : public perm_state_base { + req_state * const s; + perm_state_from_req_state(req_state * const _s) : perm_state_base(_s->cct, + _s->env, + _s->auth.identity.get(), + _s->bucket_info, + _s->perm_mask, + _s->defer_to_bucket_acls), s(_s) {} + std::optional get_request_payer() const override { + const char *request_payer = s->info.env->get("HTTP_X_AMZ_REQUEST_PAYER"); + if (!request_payer) { + bool exists; + request_payer = s->info.args.get("x-amz-request-payer", &exists).c_str(); + if (!exists) { + return false; + } + } + + if (strcasecmp(request_payer, "requester") == 0) { + return true; + } + + return std::nullopt; + } + + const char *get_referer() const override { + return s->info.env->get("HTTP_REFERER"); + } +}; + Effect eval_or_pass(const boost::optional& policy, const rgw::IAM::Environment& env, boost::optional id, @@ -1026,7 +1058,7 @@ Effect eval_user_policies(const vector& user_policies, } bool verify_user_permission(const DoutPrefixProvider* dpp, - struct req_state * const s, + perm_state_base * const s, RGWAccessControlPolicy * const user_acl, const vector& user_policies, const rgw::ARN& res, @@ -1050,11 +1082,12 @@ bool verify_user_permission(const DoutPrefixProvider* dpp, return false; } -bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state * const s, - RGWAccessControlPolicy * const user_acl, - const int perm) +bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp, + struct perm_state_base * const s, + RGWAccessControlPolicy * const user_acl, + const int perm) { - if (s->auth.identity->get_identity_type() == TYPE_ROLE) + if (s->identity->get_identity_type() == TYPE_ROLE) return false; /* S3 doesn't support account ACLs. */ @@ -1064,7 +1097,7 @@ bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp, struct req_ if ((perm & (int)s->perm_mask) != perm) return false; - return user_acl->verify_permission(dpp, *s->auth.identity, perm, perm); + return user_acl->verify_permission(dpp, *s->identity, perm, perm); } bool verify_user_permission(const DoutPrefixProvider* dpp, @@ -1072,46 +1105,40 @@ bool verify_user_permission(const DoutPrefixProvider* dpp, const rgw::ARN& res, const uint64_t op) { - return verify_user_permission(dpp, s, s->user_acl.get(), s->iam_user_policies, res, op); + perm_state_from_req_state ps(s); + return verify_user_permission(dpp, &ps, s->user_acl.get(), s->iam_user_policies, res, op); } bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state * const s, const int perm) { - return verify_user_permission_no_policy(dpp, s, s->user_acl.get(), perm); + perm_state_from_req_state ps(s); + return verify_user_permission_no_policy(dpp, &ps, s->user_acl.get(), perm); } -bool verify_requester_payer_permission(struct req_state *s) +bool verify_requester_payer_permission(struct perm_state_base *s) { if (!s->bucket_info.requester_pays) return true; - if (s->auth.identity->is_owner_of(s->bucket_info.owner)) + if (s->identity->is_owner_of(s->bucket_info.owner)) return true; - if (s->auth.identity->is_anonymous()) { + if (s->identity->is_anonymous()) { return false; } - const char *request_payer = s->info.env->get("HTTP_X_AMZ_REQUEST_PAYER"); - if (!request_payer) { - bool exists; - request_payer = s->info.args.get("x-amz-request-payer", &exists).c_str(); - if (!exists) { - return false; - } - } - - if (strcasecmp(request_payer, "requester") == 0) { - return true; + auto request_payer = s->get_request_payer(); + if (request_payer) { + return *request_payer; } return false; } bool verify_bucket_permission(const DoutPrefixProvider* dpp, - struct req_state * const s, + struct perm_state_base * const s, const rgw_bucket& bucket, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, @@ -1126,7 +1153,7 @@ bool verify_bucket_permission(const DoutPrefixProvider* dpp, if (usr_policy_res == Effect::Deny) return false; - auto r = eval_or_pass(bucket_policy, s->env, *s->auth.identity, + auto r = eval_or_pass(bucket_policy, s->env, *s->identity, op, ARN(bucket)); if (r == Effect::Allow) // It looks like S3 ACLs only GRANT permissions rather than @@ -1142,7 +1169,23 @@ bool verify_bucket_permission(const DoutPrefixProvider* dpp, return verify_bucket_permission_no_policy(dpp, s, user_acl, bucket_acl, perm); } -bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state * const s, +bool verify_bucket_permission(const DoutPrefixProvider* dpp, + struct req_state * const s, + const rgw_bucket& bucket, + RGWAccessControlPolicy * const user_acl, + RGWAccessControlPolicy * const bucket_acl, + const boost::optional& bucket_policy, + const vector& user_policies, + const uint64_t op) +{ + perm_state_from_req_state ps(s); + return verify_bucket_permission(dpp, &ps, bucket, + user_acl, bucket_acl, + bucket_policy, user_policies, + op); +} + +bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct perm_state_base * const s, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, const int perm) @@ -1153,23 +1196,38 @@ bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct re if ((perm & (int)s->perm_mask) != perm) return false; - if (bucket_acl->verify_permission(dpp, *s->auth.identity, perm, perm, - s->info.env->get("HTTP_REFERER"))) + if (bucket_acl->verify_permission(dpp, *s->identity, perm, perm, + s->get_referer())) return true; if (!user_acl) return false; - return user_acl->verify_permission(dpp, *s->auth.identity, perm, perm); + return user_acl->verify_permission(dpp, *s->identity, perm, perm); +} + +bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state * const s, + RGWAccessControlPolicy * const user_acl, + RGWAccessControlPolicy * const bucket_acl, + const int perm) +{ + perm_state_from_req_state ps(s); + return verify_bucket_permission_no_policy(dpp, + &ps, + user_acl, + bucket_acl, + perm); } bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state * const s, const int perm) { - if (!verify_requester_payer_permission(s)) + perm_state_from_req_state ps(s); + + if (!verify_requester_payer_permission(&ps)) return false; return verify_bucket_permission_no_policy(dpp, - s, + &ps, s->user_acl.get(), s->bucket_acl.get(), perm); @@ -1177,8 +1235,10 @@ bool verify_bucket_permission_no_policy(const DoutPrefixProvider* dpp, struct re bool verify_bucket_permission(const DoutPrefixProvider* dpp, struct req_state * const s, const uint64_t op) { + perm_state_from_req_state ps(s); + return verify_bucket_permission(dpp, - s, + &ps, s->bucket, s->user_acl.get(), s->bucket_acl.get(), @@ -1207,7 +1267,7 @@ int verify_bucket_owner_or_policy(struct req_state* const s, static inline bool check_deferred_bucket_perms(const DoutPrefixProvider* dpp, - struct req_state * const s, + struct perm_state_base * const s, const rgw_bucket& bucket, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, @@ -1221,7 +1281,7 @@ static inline bool check_deferred_bucket_perms(const DoutPrefixProvider* dpp, } static inline bool check_deferred_bucket_only_acl(const DoutPrefixProvider* dpp, - struct req_state * const s, + struct perm_state_base * const s, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, const uint8_t deferred_check, @@ -1231,7 +1291,7 @@ static inline bool check_deferred_bucket_only_acl(const DoutPrefixProvider* dpp, && verify_bucket_permission_no_policy(dpp, s, user_acl, bucket_acl, perm)); } -bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state * const s, +bool verify_object_permission(const DoutPrefixProvider* dpp, struct perm_state_base * const s, const rgw_obj& obj, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, @@ -1247,7 +1307,7 @@ bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state * if (usr_policy_res == Effect::Deny) return false; - auto r = eval_or_pass(bucket_policy, s->env, *s->auth.identity, op, ARN(obj)); + auto r = eval_or_pass(bucket_policy, s->env, *s->identity, op, ARN(obj)); if (r == Effect::Allow) // It looks like S3 ACLs only GRANT permissions rather than // denying them, so this should be safe. @@ -1270,7 +1330,7 @@ bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state * return false; } - bool ret = object_acl->verify_permission(dpp, *s->auth.identity, s->perm_mask, perm); + bool ret = object_acl->verify_permission(dpp, *s->identity, s->perm_mask, perm); if (ret) { return true; } @@ -1292,18 +1352,34 @@ bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state * /* we already verified the user mask above, so we pass swift_perm as the mask here, otherwise the mask might not cover the swift permissions bits */ - if (bucket_acl->verify_permission(dpp, *s->auth.identity, swift_perm, swift_perm, - s->info.env->get("HTTP_REFERER"))) + if (bucket_acl->verify_permission(dpp, *s->identity, swift_perm, swift_perm, + s->get_referer())) return true; if (!user_acl) return false; - return user_acl->verify_permission(dpp, *s->auth.identity, swift_perm, swift_perm); + return user_acl->verify_permission(dpp, *s->identity, swift_perm, swift_perm); +} + +bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state * const s, + const rgw_obj& obj, + RGWAccessControlPolicy * const user_acl, + RGWAccessControlPolicy * const bucket_acl, + RGWAccessControlPolicy * const object_acl, + const boost::optional& bucket_policy, + const vector& user_policies, + const uint64_t op) +{ + perm_state_from_req_state ps(s); + return verify_object_permission(dpp, &ps, obj, + user_acl, bucket_acl, + object_acl, bucket_policy, + user_policies, op); } bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, - struct req_state * const s, + struct perm_state_base * const s, RGWAccessControlPolicy * const user_acl, RGWAccessControlPolicy * const bucket_acl, RGWAccessControlPolicy * const object_acl, @@ -1318,7 +1394,7 @@ bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, return false; } - bool ret = object_acl->verify_permission(dpp, *s->auth.identity, s->perm_mask, perm); + bool ret = object_acl->verify_permission(dpp, *s->identity, s->perm_mask, perm); if (ret) { return true; } @@ -1340,23 +1416,25 @@ bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, /* we already verified the user mask above, so we pass swift_perm as the mask here, otherwise the mask might not cover the swift permissions bits */ - if (bucket_acl->verify_permission(dpp, *s->auth.identity, swift_perm, swift_perm, - s->info.env->get("HTTP_REFERER"))) + if (bucket_acl->verify_permission(dpp, *s->identity, swift_perm, swift_perm, + s->get_referer())) return true; if (!user_acl) return false; - return user_acl->verify_permission(dpp, *s->auth.identity, swift_perm, swift_perm); + return user_acl->verify_permission(dpp, *s->identity, swift_perm, swift_perm); } bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, struct req_state *s, int perm) { - if (!verify_requester_payer_permission(s)) + perm_state_from_req_state ps(s); + + if (!verify_requester_payer_permission(&ps)) return false; return verify_object_permission_no_policy(dpp, - s, + &ps, s->user_acl.get(), s->bucket_acl.get(), s->object_acl.get(), @@ -1365,8 +1443,10 @@ bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, struct re bool verify_object_permission(const DoutPrefixProvider* dpp, struct req_state *s, uint64_t op) { + perm_state_from_req_state ps(s); + return verify_object_permission(dpp, - s, + &ps, rgw_obj(s->bucket, s->object), s->user_acl.get(), s->bucket_acl.get(), diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 7316a0465ff..d11f6a81acf 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -2427,6 +2427,75 @@ extern void rgw_to_iso8601(const real_time& t, char *dest, int buf_size); extern void rgw_to_iso8601(const real_time& t, string *dest); extern std::string rgw_to_asctime(const utime_t& t); +struct perm_state_base { + CephContext *cct; + const rgw::IAM::Environment& env; + rgw::auth::Identity *identity; + const RGWBucketInfo& bucket_info; + int perm_mask; + bool defer_to_bucket_acls; + + perm_state_base(CephContext *_cct, + const rgw::IAM::Environment& _env, + rgw::auth::Identity *_identity, + const RGWBucketInfo& _bucket_info, + int _perm_mask, + bool _defer_to_bucket_acls) : cct(_cct), + env(_env), + identity(_identity), + bucket_info(_bucket_info), + perm_mask(_perm_mask), + defer_to_bucket_acls(_defer_to_bucket_acls) {} + virtual ~perm_state_base() {} + + virtual const char *get_referer() const = 0; + virtual std::optional get_request_payer() const = 0; + +}; + +struct perm_state : public perm_state_base { + const char *referer; + bool request_payer; + + perm_state(CephContext *_cct, + const rgw::IAM::Environment& _env, + rgw::auth::Identity *_identity, + const RGWBucketInfo& _bucket_info, + int _perm_mask, + bool _defer_to_bucket_acls, + const char *_referer, + bool _request_payer) : perm_state_base(_cct, + _env, + _identity, + _bucket_info, + _perm_mask, + _defer_to_bucket_acls), + referer(_referer), + request_payer(_request_payer) {} + + const char *get_referer() const override { + return referer; + } + + std::optional get_request_payer() const override { + return request_payer; + } +}; + +/** Check if the req_state's user has the necessary permissions + * to do the requested action */ +bool verify_bucket_permission_no_policy( + const DoutPrefixProvider* dpp, + struct perm_state_base * const s, + RGWAccessControlPolicy * const user_acl, + RGWAccessControlPolicy * const bucket_acl, + const int perm); + +bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp, + struct perm_state_base * const s, + RGWAccessControlPolicy * const user_acl, + const int perm); + /** Check if the req_state's user has the necessary permissions * to do the requested action */ rgw::IAM::Effect eval_user_policies(const vector& user_policies, -- 2.39.5