#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rgw
+using boost::none;
+using boost::optional;
+
+using rgw::IAM::ARN;
+using rgw::IAM::Effect;
+using rgw::IAM::op_to_perm;
+using rgw::IAM::Policy;
+
PerfCounters *perfcounter = NULL;
const uint32_t RGWBucketInfo::NUM_SHARDS_BLIND_BUCKET(UINT32_MAX);
}
bool verify_bucket_permission(struct req_state * const s,
+ const rgw_bucket& bucket,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
- const int perm)
+ const optional<Policy>& bucket_policy,
+ const uint64_t op)
{
- if (!bucket_acl)
+ if (!verify_requester_payer_permission(s))
return false;
- if ((perm & (int)s->perm_mask) != perm)
+ if (bucket_policy) {
+ auto r = bucket_policy->eval(s->env, *s->auth.identity, op, ARN(bucket));
+ if (r == Effect::Allow)
+ // It looks like S3 ACLs only GRANT permissions rather than
+ // denying them, so this should be safe.
+ return true;
+ else if (r == Effect::Deny)
+ return false;
+ }
+
+ const auto perm = op_to_perm(op);
+
+ return verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm);
+}
+
+bool verify_bucket_permission_no_policy(struct req_state * const s,
+ RGWAccessControlPolicy * const user_acl,
+ RGWAccessControlPolicy * const bucket_acl,
+ const int perm)
+{
+ if (!bucket_acl)
return false;
- if (!verify_requester_payer_permission(s))
+ if ((perm & (int)s->perm_mask) != perm)
return false;
if (bucket_acl->verify_permission(*s->auth.identity, perm, perm,
return user_acl->verify_permission(*s->auth.identity, perm, perm);
}
-bool verify_bucket_permission(struct req_state * const s, const int perm)
+bool verify_bucket_permission_no_policy(struct req_state * const s, const int perm)
+{
+ if (!verify_requester_payer_permission(s))
+ return false;
+
+ return verify_bucket_permission_no_policy(s,
+ s->user_acl.get(),
+ s->bucket_acl,
+ perm);
+}
+
+bool verify_bucket_permission(struct req_state * const s, const uint64_t op)
{
return verify_bucket_permission(s,
+ s->bucket,
s->user_acl.get(),
s->bucket_acl,
- perm);
+ s->iam_policy,
+ op);
+}
+
+static inline bool check_deferred_bucket_perms(struct req_state * const s,
+ const rgw_bucket& bucket,
+ RGWAccessControlPolicy * const user_acl,
+ RGWAccessControlPolicy * const bucket_acl,
+ const optional<Policy>& bucket_policy,
+ const uint8_t deferred_check,
+ const uint64_t op)
+{
+ return (s->defer_to_bucket_acls == deferred_check \
+ && verify_bucket_permission(s, bucket, user_acl, bucket_acl, bucket_policy, op));
}
-static inline bool check_deferred_bucket_acl(struct req_state * const s,
- RGWAccessControlPolicy * const user_acl,
- RGWAccessControlPolicy * const bucket_acl,
- const uint8_t deferred_check,
- const int perm)
+static inline bool check_deferred_bucket_only_acl(struct req_state * const s,
+ RGWAccessControlPolicy * const user_acl,
+ RGWAccessControlPolicy * const bucket_acl,
+ const uint8_t deferred_check,
+ const int perm)
{
return (s->defer_to_bucket_acls == deferred_check \
- && verify_bucket_permission(s, user_acl, bucket_acl, perm));
+ && verify_bucket_permission_no_policy(s, user_acl, bucket_acl, perm));
}
bool verify_object_permission(struct req_state * const s,
+ const rgw_obj& obj,
RGWAccessControlPolicy * const user_acl,
RGWAccessControlPolicy * const bucket_acl,
RGWAccessControlPolicy * const object_acl,
- const int perm)
+ const optional<Policy>& bucket_policy,
+ const uint64_t op)
{
if (!verify_requester_payer_permission(s))
return false;
- if (check_deferred_bucket_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) ||
- check_deferred_bucket_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) {
+ if (bucket_policy) {
+ auto r = bucket_policy->eval(s->env, *s->auth.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.
+ return true;
+ else if (r == Effect::Deny)
+ return false;
+ }
+
+ const auto perm = op_to_perm(op);
+
+ if (check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy,
+ RGW_DEFER_TO_BUCKET_ACLS_RECURSE, op) ||
+ check_deferred_bucket_perms(s, obj.bucket, user_acl, bucket_acl, bucket_policy,
+ RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, rgw::IAM::s3All)) {
+ return true;
+ }
+
+ if (!object_acl) {
+ return false;
+ }
+
+ bool ret = object_acl->verify_permission(*s->auth.identity, s->perm_mask, perm);
+ if (ret) {
+ return true;
+ }
+
+ if (!s->cct->_conf->rgw_enforce_swift_acls)
+ return ret;
+
+ if ((perm & (int)s->perm_mask) != perm)
+ return false;
+
+ int swift_perm = 0;
+ if (perm & (RGW_PERM_READ | RGW_PERM_READ_ACP))
+ swift_perm |= RGW_PERM_READ_OBJS;
+ if (perm & RGW_PERM_WRITE)
+ swift_perm |= RGW_PERM_WRITE_OBJS;
+
+ if (!swift_perm)
+ return false;
+
+ /* 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(*s->auth.identity, swift_perm, swift_perm,
+ s->info.env->get("HTTP_REFERER")))
+ return true;
+
+ if (!user_acl)
+ return false;
+
+ return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm);
+}
+
+bool verify_object_permission_no_policy(struct req_state * const s,
+ RGWAccessControlPolicy * const user_acl,
+ RGWAccessControlPolicy * const bucket_acl,
+ RGWAccessControlPolicy * const object_acl,
+ const int perm)
+{
+ if (check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_RECURSE, perm) ||
+ check_deferred_bucket_only_acl(s, user_acl, bucket_acl, RGW_DEFER_TO_BUCKET_ACLS_FULL_CONTROL, RGW_PERM_FULL_CONTROL)) {
return true;
}
return user_acl->verify_permission(*s->auth.identity, swift_perm, swift_perm);
}
-bool verify_object_permission(struct req_state *s, int perm)
+bool verify_object_permission_no_policy(struct req_state *s, int perm)
+{
+ if (!verify_requester_payer_permission(s))
+ return false;
+
+ return verify_object_permission_no_policy(s, s->user_acl.get(),
+ s->bucket_acl, s->object_acl,
+ perm);
+}
+
+bool verify_object_permission(struct req_state *s, uint64_t op)
{
return verify_object_permission(s,
- s->user_acl.get(),
+ rgw_obj(s->bucket, s->object),
+ s->user_acl.get(),
s->bucket_acl,
s->object_acl,
- perm);
+ s->iam_policy,
+ op);
}
class HexTable
using namespace librados;
using ceph::crypto::MD5;
using boost::optional;
+using boost::none;
+
+using rgw::IAM::ARN;
+using rgw::IAM::Effect;
+using rgw::IAM::Policy;
using rgw::IAM::Policy;
const string& tenant) {
auto i = attrs.find(RGW_ATTR_IAM_POLICY);
if (i != attrs.end()) {
- return rgw::IAM::Policy(cct, tenant, i->second);
+ return Policy(cct, tenant, i->second);
} else {
- return boost::none;
+ return none;
}
}
struct req_state *s,
RGWBucketInfo& bucket_info,
map<string, bufferlist>& bucket_attrs,
- RGWAccessControlPolicy *policy,
+ RGWAccessControlPolicy* acl,
+ optional<Policy>& policy,
rgw_bucket& bucket,
rgw_obj_key& object)
{
} else {
obj = rgw_obj(bucket, object);
}
+ policy = get_iam_policy_from_attr(s->cct, store, bucket_attrs, bucket.tenant);
+
RGWObjectCtx *obj_ctx = static_cast<RGWObjectCtx *>(s->obj_ctx);
int ret = get_obj_policy_from_attr(s->cct, store, *obj_ctx,
- bucket_info, bucket_attrs, policy, obj);
+ bucket_info, bucket_attrs, acl, obj);
if (ret == -ENOENT) {
/* object does not exist checking the bucket's ACL to make sure
that we send a proper error code */
if (prefetch_data) {
store->set_prefetch_data(s->obj_ctx, obj);
}
- ret = read_obj_policy(store, s, s->bucket_info, s->bucket_attrs, s->object_acl, s->bucket, s->object);
+ ret = read_obj_policy(store, s, s->bucket_info, s->bucket_attrs, s->object_acl, s->iam_policy, s->bucket, s->object);
}
return ret;
store->set_prefetch_data(s->obj_ctx, obj);
}
- if (!verify_object_permission(s, RGW_PERM_READ)) {
+ if (torrent.get_flag()) {
+ if (obj.key.instance.empty()) {
+ action = rgw::IAM::s3GetObjectTorrent;
+ } else {
+ action = rgw::IAM::s3GetObjectVersionTorrent;
+ }
+ } else {
+ if (obj.key.instance.empty()) {
+ action = rgw::IAM::s3GetObject;
+ } else {
+ action = rgw::IAM::s3GetObjectVersion;
+ }
+ }
+
+ if (!verify_object_permission(s, action)) {
return -EACCES;
}
int RGWGetObj::read_user_manifest_part(rgw_bucket& bucket,
const rgw_bucket_dir_entry& ent,
- RGWAccessControlPolicy * const bucket_policy,
+ RGWAccessControlPolicy * const bucket_acl,
+ const optional<Policy>& bucket_policy,
const off_t start_ofs,
const off_t end_ofs)
{
ldout(s->cct, 2) << "overriding permissions due to system operation" << dendl;
} else if (s->auth.identity->is_admin_of(s->user->user_id)) {
ldout(s->cct, 2) << "overriding permissions due to admin operation" << dendl;
- } else if (!verify_object_permission(s, s->user_acl.get(), bucket_policy,
- &obj_policy, RGW_PERM_READ)) {
+ } else if (!verify_object_permission(s, part, s->user_acl.get(), bucket_acl,
+ &obj_policy, bucket_policy, action)) {
return -EPERM;
}
const off_t end,
RGWBucketInfo *pbucket_info,
const string& obj_prefix,
- RGWAccessControlPolicy * const bucket_policy,
+ RGWAccessControlPolicy * const bucket_acl,
+ const optional<Policy>& bucket_policy,
uint64_t * const ptotal_len,
uint64_t * const pobj_size,
string * const pobj_sum,
int (*cb)(rgw_bucket& bucket,
const rgw_bucket_dir_entry& ent,
- RGWAccessControlPolicy * const bucket_policy,
+ RGWAccessControlPolicy * const bucket_acl,
+ const optional<Policy>& bucket_policy,
off_t start_ofs,
off_t end_ofs,
void *param),
len_count += end_ofs - start_ofs;
if (cb) {
- r = cb(bucket, ent, bucket_policy, start_ofs, end_ofs, cb_param);
+ r = cb(bucket, ent, bucket_acl, bucket_policy, start_ofs, end_ofs, cb_param);
if (r < 0) {
return r;
}
}
struct rgw_slo_part {
- RGWAccessControlPolicy *bucket_policy;
+ RGWAccessControlPolicy *bucket_acl = nullptr;
+ Policy* bucket_policy = nullptr;
rgw_bucket bucket;
string obj_name;
- uint64_t size;
+ uint64_t size = 0;
string etag;
-
- rgw_slo_part() : bucket_policy(NULL), size(0) {}
};
static int iterate_slo_parts(CephContext *cct,
map<uint64_t, rgw_slo_part>& slo_parts,
int (*cb)(rgw_bucket& bucket,
const rgw_bucket_dir_entry& ent,
- RGWAccessControlPolicy *bucket_policy,
+ RGWAccessControlPolicy *bucket_acl,
+ const optional<Policy>& bucket_policy,
off_t start_ofs,
off_t end_ofs,
void *param),
if (found_start) {
if (cb) {
- int r = cb(part.bucket, ent, part.bucket_policy, start_ofs, end_ofs, cb_param);
- if (r < 0)
+ // SLO is a Swift thing, and Swift has no knowledge of S3 Policies.
+ int r = cb(part.bucket, ent, part.bucket_acl,
+ (part.bucket_policy ?
+ optional<Policy>(*part.bucket_policy) : none),
+ start_ofs, end_ofs, cb_param);
+ if (r < 0)
return r;
}
}
static int get_obj_user_manifest_iterate_cb(rgw_bucket& bucket,
const rgw_bucket_dir_entry& ent,
- RGWAccessControlPolicy * const bucket_policy,
+ RGWAccessControlPolicy * const bucket_acl,
+ const optional<Policy>& bucket_policy,
const off_t start_ofs,
const off_t end_ofs,
void * const param)
{
RGWGetObj *op = static_cast<RGWGetObj *>(param);
- return op->read_user_manifest_part(bucket, ent, bucket_policy, start_ofs, end_ofs);
+ return op->read_user_manifest_part(bucket, ent, bucket_acl, bucket_policy, start_ofs, end_ofs);
}
int RGWGetObj::handle_user_manifest(const char *prefix)
rgw_bucket bucket;
- RGWAccessControlPolicy _bucket_policy(s->cct);
- RGWAccessControlPolicy *bucket_policy;
+ RGWAccessControlPolicy _bucket_acl(s->cct);
+ RGWAccessControlPolicy *bucket_acl;
+ optional<Policy> _bucket_policy;
+ optional<Policy>* bucket_policy;
RGWBucketInfo bucket_info;
RGWBucketInfo *pbucket_info;
}
bucket = bucket_info.bucket;
pbucket_info = &bucket_info;
- bucket_policy = &_bucket_policy;
- r = read_bucket_policy(store, s, bucket_info, bucket_attrs, bucket_policy, bucket);
+ bucket_acl = &_bucket_acl;
+ r = read_bucket_policy(store, s, bucket_info, bucket_attrs, bucket_acl, bucket);
if (r < 0) {
ldout(s->cct, 0) << "failed to read bucket policy" << dendl;
return r;
}
+ _bucket_policy = get_iam_policy_from_attr(s->cct, store, bucket_attrs,
+ bucket_info.bucket.tenant);
+ bucket_policy = &_bucket_policy;
} else {
bucket = s->bucket;
pbucket_info = &s->bucket_info;
- bucket_policy = s->bucket_acl;
+ bucket_acl = s->bucket_acl;
+ bucket_policy = &s->iam_policy;
}
/* dry run to find out:
* - overall DLO's content size,
* - md5 sum of overall DLO's content (for etag of Swift API). */
int r = iterate_user_manifest_parts(s->cct, store, ofs, end,
- pbucket_info, obj_prefix, bucket_policy,
+ pbucket_info, obj_prefix, bucket_acl, *bucket_policy,
&total_len, &s->obj_size, &lo_etag,
nullptr /* cb */, nullptr /* cb arg */);
if (r < 0) {
}
r = iterate_user_manifest_parts(s->cct, store, ofs, end,
- pbucket_info, obj_prefix, bucket_policy,
+ pbucket_info, obj_prefix, bucket_acl, *bucket_policy,
nullptr, nullptr, nullptr,
get_obj_user_manifest_iterate_cb, (void *)this);
if (r < 0) {
}
ldout(s->cct, 2) << "RGWGetObj::handle_slo_manifest()" << dendl;
- list<RGWAccessControlPolicy> allocated_policies;
- map<string, RGWAccessControlPolicy *> policies;
+ vector<RGWAccessControlPolicy> allocated_acls;
+ map<string, pair<RGWAccessControlPolicy *, optional<Policy>>> policies;
map<string, rgw_bucket> buckets;
map<uint64_t, rgw_slo_part> slo_parts;
string obj_name = path.substr(pos_sep + 1);
rgw_bucket bucket;
- RGWAccessControlPolicy *bucket_policy;
+ RGWAccessControlPolicy *bucket_acl;
+ Policy* bucket_policy;
if (bucket_name.compare(s->bucket.name) != 0) {
const auto& piter = policies.find(bucket_name);
if (piter != policies.end()) {
- bucket_policy = piter->second;
- bucket = buckets[bucket_name];
+ bucket_acl = piter->second.first;
+ bucket_policy = piter->second.second.get_ptr();
+ bucket = buckets[bucket_name];
} else {
- allocated_policies.push_back(RGWAccessControlPolicy(s->cct));
- RGWAccessControlPolicy& _bucket_policy = allocated_policies.back();
+ allocated_acls.push_back(RGWAccessControlPolicy(s->cct));
+ RGWAccessControlPolicy& _bucket_acl = allocated_acls.back();
RGWBucketInfo bucket_info;
map<string, bufferlist> bucket_attrs;
return r;
}
bucket = bucket_info.bucket;
- bucket_policy = &_bucket_policy;
- r = read_bucket_policy(store, s, bucket_info, bucket_attrs, bucket_policy,
+ bucket_acl = &_bucket_acl;
+ r = read_bucket_policy(store, s, bucket_info, bucket_attrs, bucket_acl,
bucket);
if (r < 0) {
- ldout(s->cct, 0) << "failed to read bucket policy for bucket "
+ ldout(s->cct, 0) << "failed to read bucket ACL for bucket "
<< bucket << dendl;
return r;
- }
- buckets[bucket_name] = bucket;
- policies[bucket_name] = bucket_policy;
+ }
+ auto _bucket_policy = get_iam_policy_from_attr(
+ s->cct, store, bucket_attrs, bucket_info.bucket.tenant);
+ bucket_policy = _bucket_policy.get_ptr();
+ buckets[bucket_name] = bucket;
+ policies[bucket_name] = make_pair(bucket_acl, _bucket_policy);
}
} else {
bucket = s->bucket;
- bucket_policy = s->bucket_acl;
+ bucket_acl = s->bucket_acl;
+ bucket_policy = s->iam_policy.get_ptr();
}
rgw_slo_part part;
+ part.bucket_acl = bucket_acl;
part.bucket_policy = bucket_policy;
part.bucket = bucket;
part.obj_name = obj_name;
int RGWStatBucket::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_READ)) {
+ // This (a HEAD request on a bucket) is governed by the s3:ListBucket permission.
+ if (!verify_bucket_permission(s, rgw::IAM::s3ListBucket)) {
return -EACCES;
}
int RGWListBucket::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_READ)) {
+ op_ret = get_params();
+ if (op_ret < 0) {
+ return op_ret;
+ }
+
+ if (!verify_bucket_permission(s,
+ list_versions ?
+ rgw::IAM::s3ListBucketVersions :
+ rgw::IAM::s3ListBucket)) {
return -EACCES;
}
return;
}
- op_ret = get_params();
- if (op_ret < 0)
- return;
-
if (need_container_stats()) {
map<string, RGWBucketEnt> m;
m[s->bucket.name] = RGWBucketEnt();
int RGWDeleteBucket::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE)) {
+ if (!verify_bucket_permission(s, rgw::IAM::s3DeleteBucket)) {
return -EACCES;
}
{
if (copy_source) {
- RGWAccessControlPolicy cs_policy(s->cct);
+ RGWAccessControlPolicy cs_acl(s->cct);
+ optional<Policy> policy;
map<string, bufferlist> cs_attrs;
rgw_bucket cs_bucket(copy_source_bucket_info.bucket);
rgw_obj_key cs_object(copy_source_object_name, copy_source_version_id);
store->set_prefetch_data(s->obj_ctx, obj);
/* check source object permissions */
- if (read_obj_policy(store, s, copy_source_bucket_info, cs_attrs, &cs_policy, cs_bucket, cs_object) < 0) {
+ if (read_obj_policy(store, s, copy_source_bucket_info, cs_attrs, &cs_acl, policy,
+ cs_bucket, cs_object) < 0) {
return -EACCES;
}
/* admin request overrides permission checks */
- if (! s->auth.identity->is_admin_of(cs_policy.get_owner().get_id()) &&
- ! cs_policy.verify_permission(*s->auth.identity, s->perm_mask, RGW_PERM_READ)) {
- return -EACCES;
+ if (! s->auth.identity->is_admin_of(cs_acl.get_owner().get_id())) {
+ if (policy) {
+ auto e = policy->eval(s->env, *s->auth.identity,
+ cs_object.instance.empty() ?
+ rgw::IAM::s3GetObject :
+ rgw::IAM::s3GetObjectVersion,
+ rgw::IAM::ARN(obj));
+ if (e == Effect::Deny) {
+ return -EACCES;
+ } else if (e == Effect::Pass &&
+ !cs_acl.verify_permission(*s->auth.identity, s->perm_mask,
+ RGW_PERM_READ)) {
+ return -EACCES;
+ }
+ } else if (!cs_acl.verify_permission(*s->auth.identity, s->perm_mask,
+ RGW_PERM_READ)) {
+ return -EACCES;
+ }
}
+ }
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3PutObject,
+ rgw_obj(s->bucket, s->object));
+ if (e == Effect::Allow) {
+ return 0;
+ } else if (e == Effect::Deny) {
+ return -EACCES;
+ }
}
- if (!verify_bucket_permission(s, RGW_PERM_WRITE)) {
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
}
return;
}
- if (!verify_bucket_permission(s, RGW_PERM_WRITE)) {
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3PutObject,
+ rgw_obj(s->bucket, s->object));
+ if (e == Effect::Deny) {
+ op_ret = -EACCES;
+ return;
+ } else if (e == Effect::Pass && !verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
+ op_ret = -EACCES;
+ return;
+ }
+ } else if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
op_ret = -EACCES;
return;
}
int RGWPutMetadataBucket::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE)) {
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
}
int RGWPutMetadataObject::verify_permission()
{
- if (!verify_object_permission(s, RGW_PERM_WRITE)) {
+ // This looks to be something specific to Swift. We could add
+ // operations like swift:PutMetadataObject to the Policy Engine.
+ if (!verify_object_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
}
int RGWDeleteObj::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE)) {
+ if (s->iam_policy) {
+ auto r = s->iam_policy->eval(s->env, *s->auth.identity,
+ s->object.instance.empty() ?
+ rgw::IAM::s3DeleteObject :
+ rgw::IAM::s3DeleteObjectVersion,
+ ARN(s->bucket, s->object.name));
+ if (r == Effect::Allow)
+ return true;
+ else if (r == Effect::Deny)
+ return false;
+ }
+
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
}
int RGWCopyObj::verify_permission()
{
- RGWAccessControlPolicy src_policy(s->cct);
+ RGWAccessControlPolicy src_acl(s->cct);
+ optional<Policy> src_policy;
op_ret = get_params();
if (op_ret < 0)
return op_ret;
store->set_prefetch_data(s->obj_ctx, src_obj);
/* check source object permissions */
- op_ret = read_obj_policy(store, s, src_bucket_info, src_attrs, &src_policy,
- src_bucket, src_object);
+ op_ret = read_obj_policy(store, s, src_bucket_info, src_attrs, &src_acl,
+ src_policy, src_bucket, src_object);
if (op_ret < 0) {
return op_ret;
}
/* admin request overrides permission checks */
- if (! s->auth.identity->is_admin_of(src_policy.get_owner().get_id()) &&
- ! src_policy.verify_permission(*s->auth.identity, s->perm_mask,
- RGW_PERM_READ)) {
- return -EACCES;
+ if (!s->auth.identity->is_admin_of(src_acl.get_owner().get_id())) {
+ if (src_policy) {
+ auto e = src_policy->eval(s->env, *s->auth.identity,
+ src_object.instance.empty() ?
+ rgw::IAM::s3GetObject :
+ rgw::IAM::s3GetObjectVersion,
+ ARN(src_obj));
+ if (e == Effect::Deny) {
+ return -EACCES;
+ } else if (e == Effect::Pass &&
+ !src_acl.verify_permission(*s->auth.identity, s->perm_mask,
+ RGW_PERM_READ)) {
+ return -EACCES;
+ }
+ } else if (!src_acl.verify_permission(*s->auth.identity,
+ s->perm_mask,
+ RGW_PERM_READ)) {
+ return -EACCES;
+ }
}
}
{
bool perm;
if (!s->object.empty()) {
- perm = verify_object_permission(s, RGW_PERM_READ_ACP);
+ perm = verify_object_permission(s,
+ s->object.instance.empty() ?
+ rgw::IAM::s3GetObjectAcl :
+ rgw::IAM::s3GetObjectVersionAcl);
} else {
- perm = verify_bucket_permission(s, RGW_PERM_READ_ACP);
+ perm = verify_bucket_permission(s, rgw::IAM::s3GetObjectAcl);
}
if (!perm)
return -EACCES;
{
bool perm;
if (!s->object.empty()) {
- perm = verify_object_permission(s, RGW_PERM_WRITE_ACP);
+ perm = verify_object_permission(s,
+ s->object.instance.empty() ?
+ rgw::IAM::s3PutObjectAcl :
+ rgw::IAM::s3PutObjectVersionAcl);
} else {
- perm = verify_bucket_permission(s, RGW_PERM_WRITE_ACP);
+ perm = verify_bucket_permission(s, rgw::IAM::s3PutBucketAcl);
}
if (!perm)
return -EACCES;
int RGWGetLC::verify_permission()
{
bool perm;
- perm = verify_bucket_permission(s, RGW_PERM_READ_ACP);
+ perm = verify_bucket_permission(s, rgw::IAM::s3GetLifecycleConfiguration);
if (!perm)
return -EACCES;
int RGWPutLC::verify_permission()
{
bool perm;
- perm = verify_bucket_permission(s, RGW_PERM_WRITE_ACP);
+ perm = verify_bucket_permission(s, rgw::IAM::s3PutLifecycleConfiguration);
if (!perm)
return -EACCES;
int RGWDeleteLC::verify_permission()
{
bool perm;
- perm = verify_bucket_permission(s, RGW_PERM_WRITE_ACP);
+ perm = verify_bucket_permission(s, rgw::IAM::s3PutLifecycleConfiguration);
if (!perm)
return -EACCES;
int RGWInitMultipart::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE))
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3PutObject,
+ rgw_obj(s->bucket, s->object));
+ if (e == Effect::Allow) {
+ return 0;
+ } else if (e == Effect::Deny) {
+ return -EACCES;
+ }
+ }
+
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
+ }
return 0;
}
int RGWCompleteMultipart::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE))
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3PutObject,
+ rgw_obj(s->bucket, s->object));
+ if (e == Effect::Allow) {
+ return 0;
+ } else if (e == Effect::Deny) {
+ return -EACCES;
+ }
+ }
+
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
+ }
return 0;
}
int RGWAbortMultipart::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE))
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3AbortMultipartUpload,
+ rgw_obj(s->bucket, s->object));
+ if (e == Effect::Allow) {
+ return 0;
+ } else if (e == Effect::Deny) {
+ return -EACCES;
+ }
+ }
+
+ if (!verify_bucket_permission_no_policy(s, RGW_PERM_WRITE)) {
return -EACCES;
+ }
return 0;
}
int RGWListMultipart::verify_permission()
{
- if (!verify_object_permission(s, RGW_PERM_READ))
+ if (!verify_object_permission(s, rgw::IAM::s3ListMultipartUploadParts))
return -EACCES;
return 0;
int RGWListBucketMultiparts::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_READ))
+ if (!verify_bucket_permission(s,
+ rgw::IAM::s3ListBucketMultiPartUploads))
return -EACCES;
return 0;
int RGWDeleteMultiObj::verify_permission()
{
- if (!verify_bucket_permission(s, RGW_PERM_WRITE))
+ acl_allowed = verify_bucket_permission_no_policy(s, RGW_PERM_WRITE);
+ if (!acl_allowed && !s->iam_policy)
return -EACCES;
return 0;
iter != multi_delete->objects.end() && num_processed < max_to_delete;
++iter, num_processed++) {
rgw_obj obj(bucket, *iter);
+ if (s->iam_policy) {
+ auto e = s->iam_policy->eval(s->env,
+ *s->auth.identity,
+ iter->instance.empty() ?
+ rgw::IAM::s3DeleteObject :
+ rgw::IAM::s3DeleteObjectVersion,
+ obj);
+ if ((e == Effect::Deny) ||
+ (e == Effect::Pass && !acl_allowed)) {
+ send_partial_response(*iter, false, "", -EACCES);
+ continue;
+ }
+ }
obj_ctx->obj.set_atomic(obj);
return false;
}
+ auto policy = get_iam_policy_from_attr(s->cct, store, battrs, binfo.bucket.tenant);
+
bucket_owner = bacl.get_owner();
/* We can use global user_acl because each BulkDelete request is allowed
* to work on entities from a single account only. */
- return verify_bucket_permission(s, s->user_acl.get(), &bacl, RGW_PERM_WRITE);
+ return verify_bucket_permission(s, binfo.bucket, s->user_acl.get(),
+ &bacl, policy, rgw::IAM::s3DeleteBucket);
}
bool RGWBulkDelete::Deleter::delete_single(const acct_path_t& path)
}
}
- return boost::none;
+ return none;
}
std::pair<std::string, std::string>
bool RGWBulkUploadOp::handle_file_verify_permission(RGWBucketInfo& binfo,
+ const rgw_obj& obj,
std::map<std::string, ceph::bufferlist>& battrs,
ACLOwner& bucket_owner /* out */)
{
return false;
}
+ auto policy = get_iam_policy_from_attr(s->cct, store, battrs, binfo.bucket.tenant);
+
bucket_owner = bacl.get_owner();
- return verify_bucket_permission(s, s->user_acl.get(), &bacl, RGW_PERM_WRITE);
+ if (policy) {
+ auto e = policy->eval(s->env, *s->auth.identity,
+ rgw::IAM::s3PutObject, obj);
+ if (e == Effect::Allow) {
+ return true;
+ } else if (e == Effect::Deny) {
+ return false;
+ }
+ }
+
+ return verify_bucket_permission_no_policy(s, s->user_acl.get(),
+ &bacl, RGW_PERM_WRITE);
}
int RGWBulkUploadOp::handle_file(const boost::string_ref path,
return op_ret;
}
- if (! handle_file_verify_permission(binfo, battrs, bowner)) {
+ if (! handle_file_verify_permission(binfo,
+ rgw_obj(binfo.bucket, object),
+ battrs, bowner)) {
ldout(s->cct, 20) << "bulk upload: object creation unauthorized" << dendl;
op_ret = -EACCES;
return op_ret;
int RGWSetAttrs::verify_permission()
{
+ // This looks to be part of the RGW-NFS machinery and has no S3 or
+ // Swift equivalent.
bool perm;
if (!s->object.empty()) {
- perm = verify_object_permission(s, RGW_PERM_WRITE);
+ perm = verify_object_permission_no_policy(s, RGW_PERM_WRITE);
} else {
- perm = verify_bucket_permission(s, RGW_PERM_WRITE);
+ perm = verify_bucket_permission_no_policy(s, RGW_PERM_WRITE);
}
if (!perm)
return -EACCES;