From 0884e990048afdd9afda64f8120499f15722e7d3 Mon Sep 17 00:00:00 2001 From: Ali Masarwa Date: Wed, 29 Jan 2025 14:09:22 +0200 Subject: [PATCH] RGW | bucket notifications: support cross tenant operations Signed-off-by: Ali Masarwa --- src/rgw/rgw_rest_pubsub.cc | 15 ++++--- src/test/rgw/bucket_notification/test_bn.py | 45 ++++++++++++++------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/rgw/rgw_rest_pubsub.cc b/src/rgw/rgw_rest_pubsub.cc index f1ffe09cf2561..a78351d4e832c 100644 --- a/src/rgw/rgw_rest_pubsub.cc +++ b/src/rgw/rgw_rest_pubsub.cc @@ -560,7 +560,7 @@ class RGWPSGetTopicOp : public RGWOp { if (ret < 0) { return ret; } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); ret = ps.get_topic(this, topic_name, result, y, nullptr); if (ret < 0) { ldpp_dout(this, 4) << "failed to get topic '" << topic_name << "', ret=" << ret << dendl; @@ -646,7 +646,7 @@ class RGWPSGetTopicAttributesOp : public RGWOp { if (ret < 0) { return ret; } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); ret = ps.get_topic(this, topic_name, result, y, nullptr); if (ret < 0) { ldpp_dout(this, 4) << "failed to get topic '" << topic_name << "', ret=" << ret << dendl; @@ -811,7 +811,7 @@ class RGWPSSetTopicAttributesOp : public RGWOp { return ret; } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); ret = ps.get_topic(this, topic_name, result, y, nullptr); if (ret < 0) { ldpp_dout(this, 4) << "failed to get topic '" << topic_name @@ -884,8 +884,7 @@ void RGWPSSetTopicAttributesOp::execute(optional_yield y) { if (!already_persistent && topic_needs_queue(dest)) { // initialize the persistent queue's location, using ':' as the namespace // delimiter because its inclusion in a TopicName would break ARNs - dest.persistent_queue = string_cat_reserve( - get_account_or_tenant(s->owner.id), ":", topic_name); + dest.persistent_queue = string_cat_reserve(topic_arn.account, ":", topic_name); op_ret = driver->add_persistent_topic(this, y, dest.persistent_queue); if (op_ret < 0) { @@ -905,7 +904,7 @@ void RGWPSSetTopicAttributesOp::execute(optional_yield y) { return; } } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); op_ret = ps.create_topic(this, topic_name, dest, topic_arn.to_string(), opaque_data, topic_owner, policy_text, y); if (op_ret < 0) { @@ -947,7 +946,7 @@ class RGWPSDeleteTopicOp : public RGWOp { return ret; } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); rgw_pubsub_topic result; ret = ps.get_topic(this, topic_name, result, y, nullptr); if (ret == -ENOENT) { @@ -1030,7 +1029,7 @@ void RGWPSDeleteTopicOp::execute(optional_yield y) { return; } - const RGWPubSub ps(driver, get_account_or_tenant(s->owner.id), *s->penv.site); + const RGWPubSub ps(driver, topic_arn.account, *s->penv.site); op_ret = ps.remove_topic(this, topic_name, y); if (op_ret < 0 && op_ret != -ENOENT) { ldpp_dout(this, 4) << "failed to remove topic '" << topic_name << ", ret=" << op_ret << dendl; diff --git a/src/test/rgw/bucket_notification/test_bn.py b/src/test/rgw/bucket_notification/test_bn.py index 665fbca74949b..23e819d74a420 100644 --- a/src/test/rgw/bucket_notification/test_bn.py +++ b/src/test/rgw/bucket_notification/test_bn.py @@ -4631,11 +4631,10 @@ def test_ps_s3_list_topics_v1(): tenant_topic_conf.del_config(tenant_topic_arn2) -@attr('basic_test') -def test_ps_s3_topic_permissions(): +def ps_s3_topic_permissions(another_tenant=""): """ test s3 topic set/get/delete permissions """ conn1 = connection() - conn2, arn2 = another_user() + conn2, arn2 = another_user(tenant=another_tenant) zonegroup = get_config_zonegroup() bucket_name = gen_bucket_name() topic_name = bucket_name + TOPIC_SUFFIX @@ -4658,17 +4657,20 @@ def test_ps_s3_topic_permissions(): topic_arn = topic_conf.set_config() topic_conf2 = PSTopicS3(conn2, topic_name, zonegroup, endpoint_args=endpoint_args) - try: - # 2nd user tries to override the topic - topic_arn = topic_conf2.set_config() - assert False, "'AuthorizationError' error is expected" - except ClientError as err: - if 'Error' in err.response: - assert_equal(err.response['Error']['Code'], 'AuthorizationError') - else: - assert_equal(err.response['Code'], 'AuthorizationError') - except Exception as err: - print('unexpected error type: '+type(err).__name__) + # only on the same tenant we can try to override the topic + if another_tenant == "": + try: + # 2nd user tries to override the topic + topic_arn = topic_conf2.set_config() + assert False, "'AuthorizationError' error is expected" + except ClientError as err: + if 'Error' in err.response: + assert_equal(err.response['Error']['Code'], 'AuthorizationError') + else: + assert_equal(err.response['Code'], 'AuthorizationError') + except Exception as err: + print('unexpected error type: '+type(err).__name__) + assert False, "'AuthorizationError' error is expected" # 2nd user tries to fetch the topic _, status = topic_conf2.get_config(topic_arn=topic_arn) @@ -4685,6 +4687,7 @@ def test_ps_s3_topic_permissions(): assert_equal(err.response['Code'], 'AuthorizationError') except Exception as err: print('unexpected error type: '+type(err).__name__) + assert False, "'AuthorizationError' error is expected" # create bucket for conn2 and try publishing notification to topic _ = conn2.create_bucket(bucket_name) @@ -4703,6 +4706,7 @@ def test_ps_s3_topic_permissions(): assert_equal(err.response['Code'], 'AccessDenied') except Exception as err: print('unexpected error type: '+type(err).__name__) + assert False, "'AuthorizationError' error is expected" try: # 2nd user tries to delete the topic @@ -4715,9 +4719,10 @@ def test_ps_s3_topic_permissions(): assert_equal(err.response['Code'], 'AuthorizationError') except Exception as err: print('unexpected error type: '+type(err).__name__) + assert False, "'AuthorizationError' error is expected" # Topic policy is now added by the 1st user to allow 2nd user. - topic_policy = topic_policy.replace("Deny", "Allow") + topic_policy = topic_policy.replace("Deny", "Allow") topic_conf = PSTopicS3(conn1, topic_name, zonegroup, endpoint_args=endpoint_args, policy_text=topic_policy) topic_arn = topic_conf.set_config() # 2nd user try to fetch topic again @@ -4740,6 +4745,16 @@ def test_ps_s3_topic_permissions(): conn2.delete_bucket(bucket_name) +@attr('basic_test') +def test_ps_s3_topic_permissions_same_tenant(): + ps_s3_topic_permissions() + + +@attr('basic_test') +def test_ps_s3_topic_permissions_cross_tenant(): + ps_s3_topic_permissions(another_tenant="boom") + + @attr('basic_test') def test_ps_s3_topic_no_permissions(): """ test s3 topic set/get/delete permissions """ -- 2.39.5