From ad71c927b30ed2a111b82c0109fad8f1c7e60375 Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Mon, 6 Nov 2023 19:20:34 +0000 Subject: [PATCH] Allow network owner reader to get subnets This patch is a follow up of [1]. "get_subnet" is a read-only operation; it should be possible for network readers to retrieve the subnet too. NOTE: the release note refers to this patch and [1]. Because [1] has been backported up to 2023.2, this patch should be backported too. [1]https://review.opendev.org/q/Iae2e3a31eb65d68dc0d3d0f9dd9fc8cf83260769 Related-Bug: #2038646 Change-Id: I05aeebe1db8ea7cadb292e60b5b322069a557c16 --- neutron/conf/policies/subnet.py | 4 +- .../tests/unit/conf/policies/test_subnet.py | 171 ++++++++++++++++++ ...net_policies_updated-ec1ddc477757b441.yaml | 7 + 3 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/subnet_policies_updated-ec1ddc477757b441.yaml diff --git a/neutron/conf/policies/subnet.py b/neutron/conf/policies/subnet.py index 05bbfa11b9a..0cf7f589701 100644 --- a/neutron/conf/policies/subnet.py +++ b/neutron/conf/policies/subnet.py @@ -117,7 +117,7 @@ rules = [ base.PROJECT_READER, 'rule:shared', 'rule:external_network', - base.ADMIN_OR_NET_OWNER_MEMBER, + base.ADMIN_OR_NET_OWNER_READER, ), scope_types=['project'], description='Get a subnet', @@ -150,7 +150,7 @@ rules = [ base.PROJECT_READER, 'rule:shared', 'rule:external_network', - base.ADMIN_OR_NET_OWNER_MEMBER, + base.ADMIN_OR_NET_OWNER_READER, ), scope_types=['project'], description='Get the subnet tags', diff --git a/neutron/tests/unit/conf/policies/test_subnet.py b/neutron/tests/unit/conf/policies/test_subnet.py index 365176bc84e..dfcdc565e5a 100644 --- a/neutron/tests/unit/conf/policies/test_subnet.py +++ b/neutron/tests/unit/conf/policies/test_subnet.py @@ -79,6 +79,13 @@ class SubnetAPITestCase(base.PolicyBaseTestCase): 'network_id': self.ext_alt_network['id'], 'ext_parent_network_id': self.ext_alt_network['id'], 'router:external': True} + # This is the case where the network belongs to the project but not + # the subnet. + self.alt_target_own_net = { + 'project_id': self.alt_project_id, + 'tenant_id': self.alt_project_id, + 'network_id': self.network['id'], + 'ext_parent_network_id': self.network['id']} def get_network(context, id, fields=None): return networks.get(id) @@ -109,6 +116,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'create_subnet', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'create_subnet', self.alt_target_own_net) def test_create_subnet_segment_id(self): self.assertRaises( @@ -124,6 +135,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'create_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'create_subnet:segment_id', self.alt_target_own_net) def test_create_subnet_service_types(self): self.assertRaises( @@ -139,6 +154,11 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'create_subnet:service_types', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'create_subnet:service_types', + self.alt_target_own_net) def test_create_subnets_tags(self): self.assertRaises( @@ -153,6 +173,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'create_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'create_subnets_tags', self.alt_target_own_net) def test_get_subnet(self): self.assertRaises( @@ -171,6 +195,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'get_subnet', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'get_subnet', self.alt_target_own_net) def test_get_subnet_segment_id(self): self.assertRaises( @@ -185,6 +213,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'get_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'get_subnet:segment_id', self.alt_target_own_net) def test_get_subnets_tags(self): self.assertRaises( @@ -203,6 +235,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'get_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'get_subnets_tags', self.alt_target_own_net) def test_update_subnet(self): self.assertRaises( @@ -217,6 +253,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'update_subnet', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'update_subnet', self.alt_target_own_net) def test_update_subnet_segment_id(self): self.assertRaises( @@ -232,6 +272,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'update_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'update_subnet:segment_id', self.alt_target_own_net) def test_update_subnet_service_types(self): self.assertRaises( @@ -247,6 +291,11 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'update_subnet:service_types', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'update_subnet:service_types', + self.alt_target_own_net) def test_update_subnets_tags(self): self.assertRaises( @@ -261,6 +310,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'update_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'update_subnets_tags', self.alt_target_own_net) def test_delete_subnet(self): self.assertRaises( @@ -275,6 +328,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'delete_subnet', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'delete_subnet', self.alt_target_own_net) def test_delete_subnets_tags(self): self.assertRaises( @@ -289,6 +346,10 @@ class SystemAdminTests(SubnetAPITestCase): base_policy.InvalidScope, policy.enforce, self.context, 'delete_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.InvalidScope, + policy.enforce, + self.context, 'delete_subnets_tags', self.alt_target_own_net) class SystemMemberTests(SystemAdminTests): @@ -319,6 +380,9 @@ class AdminTests(SubnetAPITestCase): self.target_net_alt_target)) self.assertTrue( policy.enforce(self.context, 'create_subnet', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'create_subnet', + self.alt_target_own_net)) def test_create_subnet_segment_id(self): self.assertTrue( @@ -331,6 +395,10 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce( self.context, 'create_subnet:segment_id', self.alt_target)) + self.assertTrue( + policy.enforce( + self.context, 'create_subnet:segment_id', + self.alt_target_own_net)) def test_create_subnet_service_types(self): self.assertTrue( @@ -343,6 +411,10 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce( self.context, 'create_subnet:service_types', self.alt_target)) + self.assertTrue( + policy.enforce( + self.context, 'create_subnet:service_types', + self.alt_target_own_net)) def test_create_subnets_tags(self): self.assertTrue( @@ -353,6 +425,9 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce(self.context, 'create_subnets_tags', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'create_subnets_tags', + self.alt_target_own_net)) def test_get_subnet(self): self.assertTrue( @@ -365,6 +440,9 @@ class AdminTests(SubnetAPITestCase): self.target_net_ext_alt_target)) self.assertTrue( policy.enforce(self.context, 'get_subnet', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'get_subnet', + self.alt_target_own_net)) def test_get_subnet_segment_id(self): self.assertTrue( @@ -375,6 +453,10 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce( self.context, 'get_subnet:segment_id', self.alt_target)) + self.assertTrue( + policy.enforce( + self.context, 'get_subnet:segment_id', + self.alt_target_own_net)) def test_get_subnets_tags(self): self.assertTrue( @@ -387,6 +469,9 @@ class AdminTests(SubnetAPITestCase): self.target_net_ext_alt_target)) self.assertTrue( policy.enforce(self.context, 'get_subnets_tags', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'get_subnets_tags', + self.alt_target_own_net)) def test_update_subnet(self): self.assertTrue( @@ -396,6 +481,9 @@ class AdminTests(SubnetAPITestCase): self.target_net_alt_target)) self.assertTrue( policy.enforce(self.context, 'update_subnet', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'update_subnet', + self.alt_target_own_net)) def test_update_subnet_segment_id(self): self.assertTrue( @@ -408,6 +496,10 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce( self.context, 'update_subnet:segment_id', self.alt_target)) + self.assertTrue( + policy.enforce( + self.context, 'update_subnet:segment_id', + self.alt_target_own_net)) def test_update_subnet_service_types(self): self.assertTrue( @@ -430,6 +522,9 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce(self.context, 'update_subnets_tags', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'update_subnets_tags', + self.alt_target_own_net)) def test_delete_subnet(self): self.assertTrue( @@ -439,6 +534,9 @@ class AdminTests(SubnetAPITestCase): self.target_net_alt_target)) self.assertTrue( policy.enforce(self.context, 'delete_subnet', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'delete_subnet', + self.alt_target_own_net)) def test_delete_subnets_tags(self): self.assertTrue( @@ -449,6 +547,9 @@ class AdminTests(SubnetAPITestCase): self.assertTrue( policy.enforce(self.context, 'delete_subnets_tags', self.alt_target)) + self.assertTrue( + policy.enforce(self.context, 'delete_subnets_tags', + self.alt_target_own_net)) class ProjectManagerTests(AdminTests): @@ -468,6 +569,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnet', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'create_subnet', + self.alt_target_own_net)) def test_create_subnet_segment_id(self): self.assertRaises( @@ -483,6 +587,10 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'create_subnet:segment_id', self.alt_target_own_net) def test_create_subnet_service_types(self): self.assertRaises( @@ -498,6 +606,11 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnet:service_types', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'create_subnet:service_types', + self.alt_target_own_net) def test_create_subnets_tags(self): self.assertTrue( @@ -509,6 +622,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnets_tags', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'create_subnets_tags', + self.alt_target_own_net)) def test_get_subnet(self): self.assertTrue( @@ -523,6 +639,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'get_subnet', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'get_subnet', + self.alt_target_own_net)) def test_get_subnet_segment_id(self): self.assertRaises( @@ -537,6 +656,10 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'get_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'get_subnet:segment_id', self.alt_target_own_net) def test_get_subnets_tags(self): self.assertTrue( @@ -551,6 +674,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'get_subnets_tags', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'get_subnets_tags', + self.alt_target_own_net)) def test_update_subnet(self): self.assertTrue( @@ -562,6 +688,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnet', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'update_subnet', + self.alt_target_own_net)) def test_update_subnet_segment_id(self): self.assertRaises( @@ -577,6 +706,10 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnet:segment_id', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'update_subnet:segment_id', self.alt_target_own_net) def test_update_subnet_service_types(self): self.assertRaises( @@ -592,6 +725,11 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnet:service_types', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'update_subnet:service_types', + self.alt_target_own_net) def test_update_subnets_tags(self): self.assertTrue( @@ -603,6 +741,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnets_tags', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'update_subnets_tags', + self.alt_target_own_net)) def test_delete_subnet(self): self.assertTrue( @@ -614,6 +755,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'delete_subnet', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'delete_subnet', + self.alt_target_own_net)) def test_delete_subnets_tags(self): self.assertTrue( @@ -625,6 +769,9 @@ class ProjectManagerTests(AdminTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'delete_subnets_tags', self.alt_target) + self.assertTrue( + policy.enforce(self.context, 'delete_subnets_tags', + self.alt_target_own_net)) class ProjectMemberTests(ProjectManagerTests): @@ -653,6 +800,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnet', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'create_subnet', self.alt_target_own_net) def test_create_subnets_tags(self): self.assertRaises( @@ -667,6 +818,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'create_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'create_subnets_tags', self.alt_target_own_net) def test_update_subnet(self): self.assertRaises( @@ -681,6 +836,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnet', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'update_subnet', self.alt_target_own_net) def test_update_subnets_tags(self): self.assertRaises( @@ -695,6 +854,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'update_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'update_subnets_tags', self.alt_target_own_net) def test_delete_subnet(self): self.assertRaises( @@ -709,6 +872,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'delete_subnet', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'delete_subnet', self.alt_target_own_net) def test_delete_subnets_tags(self): self.assertRaises( @@ -723,6 +890,10 @@ class ProjectReaderTests(ProjectMemberTests): base_policy.PolicyNotAuthorized, policy.enforce, self.context, 'delete_subnets_tags', self.alt_target) + self.assertRaises( + base_policy.PolicyNotAuthorized, + policy.enforce, + self.context, 'delete_subnets_tags', self.alt_target_own_net) class ServiceRoleTests(SubnetAPITestCase): diff --git a/releasenotes/notes/subnet_policies_updated-ec1ddc477757b441.yaml b/releasenotes/notes/subnet_policies_updated-ec1ddc477757b441.yaml new file mode 100644 index 00000000000..16bef408423 --- /dev/null +++ b/releasenotes/notes/subnet_policies_updated-ec1ddc477757b441.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Subnet policies have been updated to allow other users to operate on them. + Network owners and readers can now retrieve the subnet and project members + can now update and delete the subnet. For more information, see bug + `2038646 `_.