mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-20 04:12:25 -06:00
* Closes #20929: Require render_config permission for UI config rendering - Modified `ObjectRenderConfigView.has_permission()` to require both view and render_config permissions - Added `remove_permissions()` test helper to remove permissions from existing ObjectPermission objects - Added regression tests for Device and VirtualMachine render-config permission enforcement The `render_config` permission action was introduced in #16681 for API endpoints. This extends PR_7604_description to the UI render-config tabs, preventing users from viewing rendered configurations without explicit permission. * Address PR feedback * Address PR feedback
This commit is contained in:
@@ -11,6 +11,7 @@ from core.models import ObjectType
|
||||
from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
from dcim.models import *
|
||||
from extras.models import ConfigTemplate
|
||||
from ipam.models import ASN, RIR, VLAN, VRF
|
||||
from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, WeightUnitChoices
|
||||
from tenancy.models import Tenant
|
||||
@@ -2339,6 +2340,28 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
url = reverse('dcim:device_inventory', kwargs={'pk': device.pk})
|
||||
self.assertHttpStatus(self.client.get(url), 200)
|
||||
|
||||
def test_device_renderconfig(self):
|
||||
configtemplate = ConfigTemplate.objects.create(
|
||||
name='Test Config Template',
|
||||
template_code='Config for device {{ device.name }}'
|
||||
)
|
||||
device = Device.objects.first()
|
||||
device.config_template = configtemplate
|
||||
device.save()
|
||||
url = reverse('dcim:device_render-config', kwargs={'pk': device.pk})
|
||||
|
||||
# User with only view permission should NOT be able to render config
|
||||
self.add_permissions('dcim.view_device')
|
||||
self.assertHttpStatus(self.client.get(url), 403)
|
||||
|
||||
# With render_config permission added should be able to render config
|
||||
self.add_permissions('dcim.render_config_device')
|
||||
self.assertHttpStatus(self.client.get(url), 200)
|
||||
|
||||
# With view permission removed should NOT be able to render config
|
||||
self.remove_permissions('dcim.view_device')
|
||||
self.assertHttpStatus(self.client.get(url), 403)
|
||||
|
||||
|
||||
class ModuleTestCase(
|
||||
# Module does not support bulk renaming (no name field) or
|
||||
|
||||
@@ -2682,6 +2682,7 @@ class DeviceConfigContextView(ObjectConfigContextView):
|
||||
class DeviceRenderConfigView(ObjectRenderConfigView):
|
||||
queryset = Device.objects.all()
|
||||
base_template = 'dcim/device/base.html'
|
||||
additional_permissions = ['dcim.render_config_device']
|
||||
tab = ViewTab(
|
||||
label=_('Render Config'),
|
||||
weight=2100,
|
||||
|
||||
@@ -67,6 +67,16 @@ class TestCase(_TestCase):
|
||||
obj_perm.users.add(self.user)
|
||||
obj_perm.object_types.add(object_type)
|
||||
|
||||
def remove_permissions(self, *names):
|
||||
"""
|
||||
Remove a set of permissions from the test user. Accepts permission names in the form <app>.<action>_<model>.
|
||||
"""
|
||||
for name in names:
|
||||
object_type, action = resolve_permission_type(name)
|
||||
ObjectPermission.objects.filter(
|
||||
actions__contains=[action], object_types=object_type, users=self.user
|
||||
).delete()
|
||||
|
||||
#
|
||||
# Custom assertions
|
||||
#
|
||||
|
||||
@@ -4,6 +4,7 @@ from django.urls import reverse
|
||||
|
||||
from dcim.choices import InterfaceModeChoices
|
||||
from dcim.models import DeviceRole, Platform, Site
|
||||
from extras.models import ConfigTemplate
|
||||
from ipam.models import VLAN, VRF
|
||||
from utilities.testing import ViewTestCases, create_tags, create_test_device, create_test_virtualmachine
|
||||
from virtualization.choices import *
|
||||
@@ -326,6 +327,28 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
url = reverse('virtualization:virtualmachine_interfaces', kwargs={'pk': virtualmachine.pk})
|
||||
self.assertHttpStatus(self.client.get(url), 200)
|
||||
|
||||
def test_virtualmachine_renderconfig(self):
|
||||
configtemplate = ConfigTemplate.objects.create(
|
||||
name='Test Config Template',
|
||||
template_code='Config for VM {{ virtualmachine.name }}'
|
||||
)
|
||||
vm = VirtualMachine.objects.first()
|
||||
vm.config_template = configtemplate
|
||||
vm.save()
|
||||
url = reverse('virtualization:virtualmachine_render-config', kwargs={'pk': vm.pk})
|
||||
|
||||
# User with only view permission should NOT be able to render config
|
||||
self.add_permissions('virtualization.view_virtualmachine')
|
||||
self.assertHttpStatus(self.client.get(url), 403)
|
||||
|
||||
# With render_config permission added should be able to render config
|
||||
self.add_permissions('virtualization.render_config_virtualmachine')
|
||||
self.assertHttpStatus(self.client.get(url), 200)
|
||||
|
||||
# With view permission removed should NOT be able to render config
|
||||
self.remove_permissions('virtualization.view_virtualmachine')
|
||||
self.assertHttpStatus(self.client.get(url), 403)
|
||||
|
||||
|
||||
class VMInterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
||||
model = VMInterface
|
||||
|
||||
@@ -405,6 +405,7 @@ class VirtualMachineConfigContextView(ObjectConfigContextView):
|
||||
class VirtualMachineRenderConfigView(ObjectRenderConfigView):
|
||||
queryset = VirtualMachine.objects.all()
|
||||
base_template = 'virtualization/virtualmachine/base.html'
|
||||
additional_permissions = ['virtualization.render_config_virtualmachine']
|
||||
tab = ViewTab(
|
||||
label=_('Render Config'),
|
||||
weight=2100,
|
||||
|
||||
Reference in New Issue
Block a user