const std::vector<rgw::IAM::Policy>& session_policies,
const uint64_t op);
extern bool verify_object_permission(const DoutPrefixProvider* dpp, req_state *s, uint64_t op);
-extern bool verify_object_permission_no_policy(
- const DoutPrefixProvider* dpp,
- req_state * const s,
- const RGWAccessControlPolicy& user_acl,
- const RGWAccessControlPolicy& bucket_acl,
- const RGWAccessControlPolicy& object_acl,
- int perm);
extern bool verify_object_permission_no_policy(const DoutPrefixProvider* dpp, req_state *s,
int perm);
extern int verify_object_lock(
{ "s3:ReplicateDelete", s3ReplicateDelete },
{ "s3:ReplicateObject", s3ReplicateObject },
{ "s3:ReplicateTags", s3ReplicateTags },
+ { "s3:GetObjectVersionForReplication", s3GetObjectVersionForReplication },
{ "s3-object-lambda:GetObject", s3objectlambdaGetObject },
{ "s3-object-lambda:ListBucket", s3objectlambdaListBucket },
{ "iam:PutUserPolicy", iamPutUserPolicy },
case s3ReplicateTags:
return "s3:ReplicateTags";
+ case s3GetObjectVersionForReplication:
+ return "s3:GetObjectVersionForReplication";
+
case s3objectlambdaGetObject:
return "s3-object-lambda:GetObject";
s3GetObjectVersionAttributes,
s3ReplicateDelete,
s3ReplicateObject,
+ s3GetObjectVersionForReplication,
s3ReplicateTags,
s3All,
case s3ListBucketMultipartUploads:
case s3ListBucketVersions:
case s3ListMultipartUploadParts:
+ case s3GetObjectVersionForReplication:
return RGW_PERM_READ;
case s3AbortMultipartUpload:
if (has_s3_existing_tag || has_s3_resource_tag)
rgw_iam_add_objtags(this, s, has_s3_existing_tag, has_s3_resource_tag);
- if (get_torrent) {
- if (s->object->get_instance().empty()) {
- action = rgw::IAM::s3GetObjectTorrent;
- } else {
- action = rgw::IAM::s3GetObjectVersionTorrent;
+ // for system requests, assume replication context and validate replication permissions.
+ // non-impersonated or standard system requests will be handled in rgw_process_authenticated().
+ const bool is_replication_request = s->system_request;
+
+ if (is_replication_request) {
+ // check for s3:GetObject(Version)Acl permission
+ action = s->object->get_instance().empty() ? rgw::IAM::s3GetObjectAcl : rgw::IAM::s3GetObjectVersionAcl;
+ if (!verify_object_permission(this, s, action)) {
+ s->err.message = fmt::format("missing {} permission", rgw::IAM::action_bit_string(action));
+ ldpp_dout(this, 4) << "ERROR: fetching object for replication object=" << s->object << " reason=" << s->err.message << dendl;
+
+ return -EACCES;
}
- } else {
- if (s->object->get_instance().empty()) {
- action = rgw::IAM::s3GetObject;
- } else {
- action = rgw::IAM::s3GetObjectVersion;
+
+ // check for s3:GetObjectForReplication permission
+ // for versioned buckets, sync requests include `versionId`; for non-versioned, they don't.
+ // so s3:GetObjectForReplication doesn't help to be introduced as it doesn't add any value.
+ action = rgw::IAM::s3GetObjectVersionForReplication;
+ if (verify_object_permission(this, s, action)) {
+ return 0;
}
+
+ // fallback to s3:GetObject(Version) permission
+ action = s->object->get_instance().empty() ? rgw::IAM::s3GetObject : rgw::IAM::s3GetObjectVersion;
+ } else if (get_torrent) {
+ action = s->object->get_instance().empty() ? rgw::IAM::s3GetObjectTorrent : rgw::IAM::s3GetObjectVersionTorrent;
+ } else {
+ action = s->object->get_instance().empty() ? rgw::IAM::s3GetObject : rgw::IAM::s3GetObjectVersion;
}
if (!verify_object_permission(this, s, action)) {
+ s->err.message = fmt::format("missing {} permission", rgw::IAM::action_bit_string(action));
+
+ if (is_replication_request) {
+ ldpp_dout(this, 4) << "ERROR: fetching object for replication object=" << s->object << " reason=" << s->err.message << dendl;
+ }
+
return -EACCES;
}
using rgw::IAM::s3GetObjectVersionAttributes;
using rgw::IAM::s3GetPublicAccessBlock;
using rgw::IAM::s3GetReplicationConfiguration;
+using rgw::IAM::s3GetObjectVersionForReplication;
using rgw::IAM::s3ListAllMyBuckets;
using rgw::IAM::s3ListBucket;
using rgw::IAM::s3ListBucketMultipartUploads;
act2[s3GetBucketPublicAccessBlock] = 1;
act2[s3GetPublicAccessBlock] = 1;
act2[s3GetBucketEncryption] = 1;
+ act2[s3GetObjectVersionForReplication] = 1;
EXPECT_EQ(p->statements[2].action, act2);
EXPECT_EQ(p->statements[2].notaction, None);
s3allow[s3GetBucketPublicAccessBlock] = 1;
s3allow[s3GetPublicAccessBlock] = 1;
s3allow[s3GetBucketEncryption] = 1;
+ s3allow[s3GetObjectVersionForReplication] = 1;
ARN arn1(Partition::aws, Service::s3,
"", arbitrary_tenant, "mybucket");
act[s3GetPublicAccessBlock] = 1;
act[s3GetBucketPublicAccessBlock] = 1;
act[s3GetBucketEncryption] = 1;
+ act[s3GetObjectVersionForReplication] = 1;
// s3:List*
act[s3ListMultipartUploadParts] = 1;
act[s3ListBucket] = 1;