From 097f465f397e6ff1ac3a4e8edb1525b5e1172c12 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Mon, 8 Mar 2021 17:03:38 -0500 Subject: [PATCH] Fix the RBAC for attaching an EE to various objects - Organization.default_environment - Project.default_environment - JobTemplate.execution_environment - WorkflowJobTemplate.execution_environment System jobs are not editable by anyone other than a system admin, so we don't need to check. It appears that unified job templates can't be created or edited outside of the endpoints for the specific types. --- awx/main/access.py | 49 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index d2a2aa9f3b..cdb0c0eb53 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -777,6 +777,11 @@ class OrganizationAccess(NotificationAttachMixin, BaseAccess): @check_superuser def can_change(self, obj, data): + if data and data.get('default_environment'): + ee = get_object_from_data('default_environment', ExecutionEnvironment, data) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + return self.user in obj.admin_role def can_delete(self, obj): @@ -1385,14 +1390,29 @@ class ProjectAccess(NotificationAttachMixin, BaseAccess): def can_add(self, data): if not data: # So the browseable API will work return Organization.accessible_objects(self.user, 'project_admin_role').exists() - return (self.check_related('organization', Organization, data, role_field='project_admin_role', mandatory=True) and - self.check_related('credential', Credential, data, role_field='use_role')) + + if data.get('default_environment'): + ee = get_object_from_data('default_environment', ExecutionEnvironment, data) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + + return ( + self.check_related('organization', Organization, data, role_field='project_admin_role', mandatory=True) and + self.check_related('credential', Credential, data, role_field='use_role') + ) @check_superuser def can_change(self, obj, data): - return (self.check_related('organization', Organization, data, obj=obj, role_field='project_admin_role') and - self.user in obj.admin_role and - self.check_related('credential', Credential, data, obj=obj, role_field='use_role')) + if data and data.get('default_environment'): + ee = get_object_from_data('default_environment', ExecutionEnvironment, data, obj=obj) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + + return ( + self.check_related('organization', Organization, data, obj=obj, role_field='project_admin_role') and + self.user in obj.admin_role and + self.check_related('credential', Credential, data, obj=obj, role_field='use_role') + ) @check_superuser def can_start(self, obj, validate_license=True): @@ -1497,6 +1517,10 @@ class JobTemplateAccess(NotificationAttachMixin, BaseAccess): if self.user not in inventory.use_role: return False + ee = get_value(ExecutionEnvironment, 'execution_environment') + if ee and not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + project = get_value(Project, 'project') # If the user has admin access to the project (as an org admin), should # be able to proceed without additional checks. @@ -1544,6 +1568,11 @@ class JobTemplateAccess(NotificationAttachMixin, BaseAccess): if self.changes_are_non_sensitive(obj, data): return True + if data.get('execution_environment'): + ee = get_object_from_data('execution_environment', ExecutionEnvironment, data) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + for required_field, cls in (('inventory', Inventory), ('project', Project)): is_mandatory = True if not getattr(obj, '{}_id'.format(required_field)): @@ -1974,6 +2003,11 @@ class WorkflowJobTemplateAccess(NotificationAttachMixin, BaseAccess): if not data: # So the browseable API will work return Organization.accessible_objects(self.user, 'workflow_admin_role').exists() + if data.get('execution_environment'): + ee = get_object_from_data('execution_environment', ExecutionEnvironment, data) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + return ( self.check_related('organization', Organization, data, role_field='workflow_admin_role', mandatory=True) and self.check_related('inventory', Inventory, data, role_field='use_role') @@ -2023,6 +2057,11 @@ class WorkflowJobTemplateAccess(NotificationAttachMixin, BaseAccess): if self.user.is_superuser: return True + if data and data.get('execution_environment'): + ee = get_object_from_data('execution_environment', ExecutionEnvironment, data) + if not self.user.can_access(ExecutionEnvironment, 'read', ee): + return False + return ( self.check_related('organization', Organization, data, role_field='workflow_admin_role', obj=obj) and self.check_related('inventory', Inventory, data, role_field='use_role', obj=obj) and