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:
Yehuda Sadeh 2019-11-22 15:31:55 -08:00
parent 82df2faa1d
commit 1bc51e2fc8
2 changed files with 196 additions and 47 deletions

View File

@ -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(),

View File

@ -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,