diff --git a/awx/api/permissions.py b/awx/api/permissions.py index df6c88618f..867388a08d 100644 --- a/awx/api/permissions.py +++ b/awx/api/permissions.py @@ -15,7 +15,7 @@ from awx.main.utils import get_object_or_400 logger = logging.getLogger('awx.api.permissions') -__all__ = ['ModelAccessPermission', 'JobTemplateCallbackPermission', +__all__ = ['ModelAccessPermission', 'JobTemplateCallbackPermission', 'VariableDataPermission', 'TaskPermission', 'ProjectUpdatePermission', 'InventoryInventorySourcesUpdatePermission', 'UserPermission', 'IsSuperUser', 'InstanceGroupTowerPermission',] @@ -74,12 +74,8 @@ class ModelAccessPermission(permissions.BasePermission): # FIXME: For some reason this needs to return True # because it is first called with obj=None? return True - if getattr(view, 'is_variable_data', False): - return check_user_access(request.user, view.model, 'change', obj, - dict(variables=request.data)) - else: - return check_user_access(request.user, view.model, 'change', obj, - request.data) + return check_user_access(request.user, view.model, 'change', obj, + request.data) def check_patch_permissions(self, request, view, obj=None): return self.check_put_permissions(request, view, obj) @@ -163,6 +159,15 @@ class JobTemplateCallbackPermission(ModelAccessPermission): return True +class VariableDataPermission(ModelAccessPermission): + + def check_put_permissions(self, request, view, obj=None): + if not obj: + return True + return check_user_access(request.user, view.model, 'change', obj, + dict(variables=request.data)) + + class TaskPermission(ModelAccessPermission): ''' Permission checks used for API callbacks from running a task. diff --git a/awx/api/views/__init__.py b/awx/api/views/__init__.py index f8f4e82521..eb02aec10f 100644 --- a/awx/api/views/__init__.py +++ b/awx/api/views/__init__.py @@ -92,7 +92,7 @@ from awx.main.redact import UriCleaner from awx.api.permissions import ( JobTemplateCallbackPermission, TaskPermission, ProjectUpdatePermission, InventoryInventorySourcesUpdatePermission, UserPermission, - InstanceGroupTowerPermission, + InstanceGroupTowerPermission, VariableDataPermission ) from awx.api import renderers from awx.api import serializers @@ -1948,7 +1948,7 @@ class BaseVariableData(RetrieveUpdateAPIView): parser_classes = api_settings.DEFAULT_PARSER_CLASSES + [YAMLParser] renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [YAMLRenderer] - is_variable_data = True # Special flag for permissions check. + permission_classes = (VariableDataPermission,) class InventoryVariableData(BaseVariableData): diff --git a/awx/main/tests/functional/api/test_inventory.py b/awx/main/tests/functional/api/test_inventory.py index d261f3e146..78827dbe34 100644 --- a/awx/main/tests/functional/api/test_inventory.py +++ b/awx/main/tests/functional/api/test_inventory.py @@ -425,6 +425,22 @@ def test_inventory_source_vars_prohibition(post, inventory, admin_user): assert 'FOOBAR' in r.data['source_vars'][0] +@pytest.mark.django_db +@pytest.mark.parametrize('role,expect', [ + ('admin_role', 200), + ('use_role', 403), + ('adhoc_role', 403), + ('read_role', 403) +]) +def test_action_view_permissions(patch, put, get, inventory, rando, role, expect): + getattr(inventory, role).members.add(rando) + url = reverse('api:inventory_variable_data', kwargs={'pk': inventory.pk}) + # read_role and all other roles should be able to view + get(url=url, user=rando, expect=200) + patch(url=url, data={"host_filter": "bar"}, user=rando, expect=expect) + put(url=url, data={"fooooo": "bar"}, user=rando, expect=expect) + + @pytest.mark.django_db class TestInventorySourceCredential: def test_need_cloud_credential(self, inventory, admin_user, post):