diff --git a/awx/api/permissions.py b/awx/api/permissions.py index 966cf95ea5..cf29f3454a 100644 --- a/awx/api/permissions.py +++ b/awx/api/permissions.py @@ -16,8 +16,8 @@ from awx.main.utils import get_object_or_400 logger = logging.getLogger('awx.api.permissions') __all__ = ['ModelAccessPermission', 'JobTemplateCallbackPermission', - 'TaskPermission', 'ProjectUpdatePermission', 'UserPermission', - 'IsSuperUser'] + 'TaskPermission', 'ProjectUpdatePermission', 'InventoryInventorySourcesUpdatePermission', + 'UserPermission', 'IsSuperUser'] class ModelAccessPermission(permissions.BasePermission): @@ -200,6 +200,12 @@ class ProjectUpdatePermission(ModelAccessPermission): return check_user_access(request.user, view.model, 'start', project) +class InventoryInventorySourcesUpdatePermission(ModelAccessPermission): + def check_post_permissions(self, request, view, obj=None): + inventory = get_object_or_400(view.model, pk=view.kwargs['pk']) + return check_user_access(request.user, view.model, 'update', inventory) + + class UserPermission(ModelAccessPermission): def check_post_permissions(self, request, view, obj=None): if not request.data: diff --git a/awx/api/views.py b/awx/api/views.py index 5155d9ceed..06d815b394 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2311,6 +2311,7 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView): model = Inventory serializer_class = InventorySourceUpdateSerializer + permission_classes = (InventoryInventorySourcesUpdatePermission,) is_job_start = True new_in_320 = True @@ -2327,15 +2328,20 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView): inventory = self.get_object() update_data = [] for inventory_source in inventory.inventory_sources.all(): - details = {'inventory_source': inventory_source.pk, 'status': None, 'inventory_update': None} + details = {'inventory_source': inventory_source.pk, 'status': None} can_update = inventory_source.can_update + project_update = False if inventory_source.source == 'scm' and inventory_source.update_on_project_update: - if not self.request.user or self.request.user.can_access(self.model, 'update', inventory_source): + if not self.request.user or not self.request.user.can_access(Project, 'start', inventory_source.source_project): details['status'] = 'You do not have permission to update project `{}`'.format(inventory_source.source_project.name) can_update = False + else: + project_update = True if can_update: + if project_update: + details['project_update'] = inventory_source.source_project.update().id details['status'] = 'started' details['inventory_update'] = inventory_source.update().id else: @@ -2462,7 +2468,7 @@ class InventorySourceUpdateView(RetrieveAPIView): obj = self.get_object() if obj.can_update: if obj.source == 'scm' and obj.update_on_project_update: - if not self.request.user or self.request.user.can_access(self.model, 'update', obj): + if not self.request.user or not self.request.user.can_access(Project, 'start', obj.source_project): raise PermissionDenied(detail=_( 'You do not have permission to update project `{}`.'.format(obj.source_project.name))) return self._build_update_response(obj.source_project.update(), request) diff --git a/awx/main/access.py b/awx/main/access.py index 4488b09423..78d90d146a 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -566,6 +566,10 @@ class InventoryAccess(BaseAccess): # inventory to a new organization. Otherwise, just check for admin permission. return self.check_related('organization', Organization, data, obj=obj) and self.user in obj.admin_role + @check_superuser + def can_update(self, obj): + return self.user in obj.update_role + def can_delete(self, obj): is_can_admin = self.can_admin(obj, None) if not is_can_admin: