mirror of
https://github.com/ceph/ceph
synced 2025-02-21 18:17:42 +00:00
rgw: api to check bucket and object permissions without need for req_state
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
This commit is contained in:
parent
82df2faa1d
commit
1bc51e2fc8
@ -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<bool> 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>& policy,
|
||||
const rgw::IAM::Environment& env,
|
||||
boost::optional<const rgw::auth::Identity&> id,
|
||||
@ -1026,7 +1058,7 @@ Effect eval_user_policies(const vector<Policy>& 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<rgw::IAM::Policy>& 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<Policy>& bucket_policy,
|
||||
const vector<Policy>& 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<Policy>& bucket_policy,
|
||||
const vector<Policy>& 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(),
|
||||
|
@ -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<bool> 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<bool> 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<rgw::IAM::Policy>& user_policies,
|
||||
|
Loading…
Reference in New Issue
Block a user