Fixes: #17310 - Properly restrict GraphQL related object queries (#17312)

* Fixes: #17310 - Fix GraphQL restriction of related objects

* Fix some failing tests

* Fix test
This commit is contained in:
Daniel Sheppard 2024-08-30 13:22:58 -05:00 committed by GitHub
parent 91ad3f22a3
commit 4fead1c85f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 53 additions and 2 deletions

View File

@ -96,6 +96,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'status': 'planned',
}
user_permissions = ('circuits.view_provider', 'circuits.view_circuittype')
@classmethod
def setUpTestData(cls):
@ -150,6 +151,7 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
model = CircuitTermination
brief_fields = ['_occupied', 'cable', 'circuit', 'description', 'display', 'id', 'term_side', 'url']
user_permissions = ('circuits.view_circuit', )
@classmethod
def setUpTestData(cls):
@ -209,6 +211,7 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
class ProviderAccountTest(APIViewTestCases.APIViewTestCase):
model = ProviderAccount
brief_fields = ['account', 'description', 'display', 'id', 'name', 'url']
user_permissions = ('circuits.view_provider', )
@classmethod
def setUpTestData(cls):
@ -252,6 +255,7 @@ class ProviderAccountTest(APIViewTestCases.APIViewTestCase):
class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
model = ProviderNetwork
brief_fields = ['description', 'display', 'id', 'name', 'url']
user_permissions = ('circuits.view_provider', )
@classmethod
def setUpTestData(cls):

View File

@ -57,6 +57,7 @@ class DataFileTest(
):
model = DataFile
brief_fields = ['display', 'id', 'path', 'url']
user_permissions = ('core.view_datasource', )
@classmethod
def setUpTestData(cls):

View File

@ -195,6 +195,7 @@ class LocationTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_site', )
@classmethod
def setUpTestData(cls):
@ -280,6 +281,7 @@ class RackTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'status': 'planned',
}
user_permissions = ('dcim.view_site', )
@classmethod
def setUpTestData(cls):
@ -368,6 +370,7 @@ class RackReservationTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_rack', 'users.view_user')
@classmethod
def setUpTestData(cls):
@ -447,6 +450,7 @@ class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'part_number': 'ABC123',
}
user_permissions = ('dcim.view_manufacturer', )
@classmethod
def setUpTestData(cls):
@ -492,6 +496,7 @@ class ModuleTypeTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'part_number': 'ABC123',
}
user_permissions = ('dcim.view_manufacturer', )
@classmethod
def setUpTestData(cls):
@ -663,6 +668,7 @@ class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_devicetype', )
@classmethod
def setUpTestData(cls):
@ -768,6 +774,7 @@ class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_rearporttemplate', )
@classmethod
def setUpTestData(cls):
@ -905,6 +912,7 @@ class ModuleBayTemplateTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_devicetype', )
@classmethod
def setUpTestData(cls):
@ -945,6 +953,7 @@ class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_devicetype', )
@classmethod
def setUpTestData(cls):
@ -985,6 +994,7 @@ class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_devicetype', 'dcim.view_manufacturer',)
@classmethod
def setUpTestData(cls):
@ -1103,6 +1113,10 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'status': 'failed',
}
user_permissions = (
'dcim.view_site', 'dcim.view_rack', 'dcim.view_location', 'dcim.view_devicerole', 'dcim.view_devicetype',
'extras.view_configtemplate',
)
@classmethod
def setUpTestData(cls):
@ -1293,6 +1307,7 @@ class ModuleTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'serial': '1234ABCD',
}
user_permissions = ('dcim.view_modulebay', 'dcim.view_moduletype', 'dcim.view_device')
@classmethod
def setUpTestData(cls):
@ -1358,6 +1373,7 @@ class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
'description': 'New description',
}
peer_termination_type = ConsoleServerPort
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1400,6 +1416,7 @@ class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIView
'description': 'New description',
}
peer_termination_type = ConsolePort
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1442,6 +1459,7 @@ class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
'description': 'New description',
}
peer_termination_type = PowerOutlet
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1481,6 +1499,7 @@ class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCa
'description': 'New description',
}
peer_termination_type = PowerPort
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1529,6 +1548,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
'description': 'New description',
}
peer_termination_type = Interface
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1663,6 +1683,7 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase):
'description': 'New description',
}
peer_termination_type = Interface
user_permissions = ('dcim.view_device', 'dcim.view_rearport')
@classmethod
def setUpTestData(cls):
@ -1721,6 +1742,7 @@ class RearPortTest(APIViewTestCases.APIViewTestCase):
'description': 'New description',
}
peer_termination_type = Interface
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1762,6 +1784,7 @@ class ModuleBayTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1801,6 +1824,7 @@ class DeviceBayTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_device', )
@classmethod
def setUpTestData(cls):
@ -1864,6 +1888,7 @@ class InventoryItemTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
user_permissions = ('dcim.view_device', 'dcim.view_manufacturer')
@classmethod
def setUpTestData(cls):
@ -2160,6 +2185,7 @@ class VirtualChassisTest(APIViewTestCases.APIViewTestCase):
class PowerPanelTest(APIViewTestCases.APIViewTestCase):
model = PowerPanel
brief_fields = ['description', 'display', 'id', 'name', 'powerfeed_count', 'url']
user_permissions = ('dcim.view_site', )
@classmethod
def setUpTestData(cls):
@ -2212,6 +2238,7 @@ class PowerFeedTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'status': 'planned',
}
user_permissions = ('dcim.view_powerpanel', )
@classmethod
def setUpTestData(cls):

View File

@ -767,6 +767,7 @@ class FHRPGroupAssignmentTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'priority': 100,
}
user_permissions = ('ipam.view_fhrpgroup', )
@classmethod
def setUpTestData(cls):

View File

@ -36,6 +36,6 @@ schema = strawberry.Schema(
query=Query,
config=StrawberryConfig(auto_camel_case=False),
extensions=[
DjangoOptimizerExtension,
DjangoOptimizerExtension(prefetch_custom_queryset=True),
]
)

View File

@ -6,6 +6,7 @@ from rest_framework import status
from core.models import ObjectType
from dcim.models import Site, Location
from ipam.models import ASN, RIR
from users.models import ObjectPermission
from utilities.testing import disable_warnings, APITestCase, TestCase
@ -45,7 +46,6 @@ class GraphQLTestCase(TestCase):
class GraphQLAPITestCase(APITestCase):
@override_settings(LOGIN_REQUIRED=True)
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*', 'auth.user'])
def test_graphql_filter_objects(self):
"""
Test the operation of filters for GraphQL API requests.
@ -66,6 +66,7 @@ class GraphQLAPITestCase(APITestCase):
obj_perm.save()
obj_perm.users.add(self.user)
obj_perm.object_types.add(ObjectType.objects.get_for_model(Location))
obj_perm.object_types.add(ObjectType.objects.get_for_model(Site))
# A valid request should return the filtered list
url = reverse('graphql')
@ -75,6 +76,7 @@ class GraphQLAPITestCase(APITestCase):
data = json.loads(response.content)
self.assertNotIn('errors', data)
self.assertEqual(len(data['data']['location_list']), 1)
self.assertIsNotNone(data['data']['location_list'][0]['site'])
# An invalid request should return an empty list
query = '{location_list(filters: {site_id: "99999"}) {id site {id}}}' # Invalid site ID
@ -82,3 +84,12 @@ class GraphQLAPITestCase(APITestCase):
self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content)
self.assertEqual(len(data['data']['location_list']), 0)
# Removing the permissions from location should result in an empty locations list
obj_perm.object_types.remove(ObjectType.objects.get_for_model(Location))
query = '{site(id: ' + str(sites[0].pk) + ') {id locations {id}}}'
response = self.client.post(url, data={'query': query}, format="json", **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content)
self.assertNotIn('errors', data)
self.assertEqual(len(data['data']['site']['locations']), 0)

View File

@ -210,6 +210,7 @@ class ContactAssignmentTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'priority': ContactPriorityChoices.PRIORITY_INACTIVE,
}
user_permissions = ('tenancy.view_contact', )
@classmethod
def setUpTestData(cls):

View File

@ -253,6 +253,7 @@ class VMInterfaceTest(APIViewTestCases.APIViewTestCase):
'description': 'New description',
}
graphql_base_name = 'vm_interface'
user_permissions = ('virtualization.view_virtualmachine', )
@classmethod
def setUpTestData(cls):
@ -342,6 +343,7 @@ class VirtualDiskTest(APIViewTestCases.APIViewTestCase):
'size': 888,
}
graphql_base_name = 'virtual_disk'
user_permissions = ('virtualization.view_virtualmachine', )
@classmethod
def setUpTestData(cls):

View File

@ -116,6 +116,7 @@ class TunnelTerminationTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'role': TunnelTerminationRoleChoices.ROLE_PEER,
}
user_permissions = ('vpn.view_tunnel', )
@classmethod
def setUpTestData(cls):
@ -430,6 +431,7 @@ class IPSecPolicyTest(APIViewTestCases.APIViewTestCase):
class IPSecProfileTest(APIViewTestCases.APIViewTestCase):
model = IPSecProfile
brief_fields = ['description', 'display', 'id', 'name', 'url']
user_permissions = ('vpn.view_ikepolicy', 'vpn.view_ipsecpolicy')
@classmethod
def setUpTestData(cls):
@ -558,6 +560,7 @@ class L2VPNTest(APIViewTestCases.APIViewTestCase):
class L2VPNTerminationTest(APIViewTestCases.APIViewTestCase):
model = L2VPNTermination
brief_fields = ['display', 'id', 'l2vpn', 'url']
user_permissions = ('dcim.view_location', 'vpn.view_l2vpn')
@classmethod
def setUpTestData(cls):

View File

@ -114,6 +114,7 @@ class WirelessLinkTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'status': 'planned',
}
user_permissions = ('dcim.view_interface', )
@classmethod
def setUpTestData(cls):