total_len = 0;
}
+ // check for GetObject(Version)Tagging permission to include tags in response
+ auto action = s->object->get_instance().empty() ? rgw::IAM::s3GetObjectTagging : rgw::IAM::s3GetObjectVersionTagging;
+ // since we are already under s->system_request, if the request is not impersonating,
+ // it can be assumed that it is not a user-mode replication.
+ bool keep_tags = s->auth.identity->is_admin_of(s->user->get_id()) || verify_object_permission(this, s, action);
+
+ // remove tags from attrs if the user doesn't have permission
+ bufferlist tags_bl;
+ if (!keep_tags) {
+ auto iter = attrs.find(RGW_ATTR_TAGS);
+ if (iter != attrs.end()) {
+ ldpp_dout(this, 4) << "removing tags from attrs due to missing permission on " << rgw::IAM::action_bit_string(action) << dendl;
+
+ tags_bl = iter->second;
+ attrs.erase(iter);
+ }
+ }
+
/* JSON encode object metadata */
JSONFormatter jf;
jf.open_object_section("obj_metadata");
metadata_bl.append(ss.str());
dump_header(s, "Rgwx-Embedded-Metadata-Len", metadata_bl.length());
total_len += metadata_bl.length();
+
+ // restore tags
+ if (tags_bl.length()) {
+ attrs[RGW_ATTR_TAGS] = std::move(tags_bl);
+ }
}
if (s->system_request && !real_clock::is_zero(lastmod)) {
assert e.response['Error']['Code'] == 'NoSuchKey'
# check the source object has replication status set to FAILED
- # uncomment me in https://github.com/ceph/ceph/pull/62147
- # res = source.s3_client.head_object(Bucket=source_bucket_name, Key=objname)
- # assert_equal(res['ReplicationStatus'], 'FAILED')
+
+@allow_bucket_replication
+def test_bucket_replication_source_forbidden_getobjecttagging():
+ zonegroup = realm.master_zonegroup()
+ zonegroup_conns = ZonegroupConns(zonegroup)
+
+ source = zonegroup_conns.rw_zones[0]
+ dest = zonegroup_conns.rw_zones[1]
+
+ source_bucket = source.create_bucket(gen_bucket_name())
+ dest_bucket = dest.create_bucket(gen_bucket_name())
+ zonegroup_meta_checkpoint(zonegroup)
+
+ # create replication configuration
+ source.s3_client.put_bucket_replication(
+ Bucket=source_bucket.name,
+ ReplicationConfiguration={
+ 'Role': '',
+ 'Rules': [{
+ 'ID': 'rule1',
+ 'Status': 'Enabled',
+ 'Destination': {
+ 'Bucket': f'arn:aws:s3:::{dest_bucket.name}',
+ }
+ }]
+ }
+ )
+
+ # Deny myself from fetching the source object for replication
+ source.s3_client.put_bucket_policy(
+ Bucket=source_bucket.name,
+ Policy=json.dumps({
+ 'Version': '2012-10-17',
+ 'Statement': [{
+ 'Effect': 'Deny',
+ 'Principal': {'AWS': [f"arn:aws:iam:::user/{user.id}"]},
+ 'Action': 's3:GetObjectTagging',
+ 'Resource': f'arn:aws:s3:::{source_bucket.name}/*',
+ }]
+ })
+ )
+ zonegroup_meta_checkpoint(zonegroup)
+
+ # upload an object and wait for sync.
+ objname = 'dummy'
+ source.s3_client.put_object(Bucket=source_bucket.name, Key=objname, Body='foo', Tagging='key1=value1')
+ zone_data_checkpoint(dest.zone, source.zone)
+
+ # check that object exists in destination bucket without tags
+ res = dest.s3_client.get_object(Bucket=dest_bucket.name, Key=objname)
+ assert_equal(res['Body'].read().decode('utf-8'), 'foo')
+ assert 'TagCount' not in res
+
+@allow_bucket_replication
+def test_bucket_replication_source_forbidden_getobjectversiontagging():
+ zonegroup = realm.master_zonegroup()
+ zonegroup_conns = ZonegroupConns(zonegroup)
+
+ source = zonegroup_conns.rw_zones[0]
+ dest = zonegroup_conns.rw_zones[1]
+
+ source_bucket = source.create_bucket(gen_bucket_name())
+ # enable versioning
+ source.s3_client.put_bucket_versioning(
+ Bucket=source_bucket.name,
+ VersioningConfiguration={'Status': 'Enabled'}
+ )
+ dest_bucket = dest.create_bucket(gen_bucket_name())
+ zonegroup_meta_checkpoint(zonegroup)
+
+ # create replication configuration
+ source.s3_client.put_bucket_replication(
+ Bucket=source_bucket.name,
+ ReplicationConfiguration={
+ 'Role': '',
+ 'Rules': [{
+ 'ID': 'rule1',
+ 'Status': 'Enabled',
+ 'Destination': {
+ 'Bucket': f'arn:aws:s3:::{dest_bucket.name}',
+ }
+ }]
+ }
+ )
+
+ # Deny myself from fetching the source object for replication
+ source.s3_client.put_bucket_policy(
+ Bucket=source_bucket.name,
+ Policy=json.dumps({
+ 'Version': '2012-10-17',
+ 'Statement': [{
+ 'Effect': 'Deny',
+ 'Principal': {'AWS': [f"arn:aws:iam:::user/{user.id}"]},
+ 'Action': 's3:GetObjectVersionTagging',
+ 'Resource': f'arn:aws:s3:::{source_bucket.name}/*',
+ }]
+ })
+ )
+ zonegroup_meta_checkpoint(zonegroup)
+
+ # upload an object and wait for sync.
+ objname = 'dummy'
+ source.s3_client.put_object(Bucket=source_bucket.name, Key=objname, Body='foo', Tagging='key1=value1')
+ zone_data_checkpoint(dest.zone, source.zone)
+
+ # check that object exists in destination bucket without tags
+ res = dest.s3_client.get_object(Bucket=dest_bucket.name, Key=objname)
+ assert_equal(res['Body'].read().decode('utf-8'), 'foo')
+ assert 'TagCount' not in res