From 5b2adc89cfa85ec9e88aa961596f7ea9bddf53a1 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Fri, 19 Feb 2021 14:06:01 -0500 Subject: [PATCH] Make the managed_by_tower field read-only for EEs (similar to how we deal with it not being settable for Credentials) and add permissions checking for Org EE Admins. can_add: gets an explicit role to check against, `'execution_environment_admin_role'` can_change: leverages `self.check_related()` for the case where the Org is not changing, but also adds an explicit check for the EE Admin Role when the Org is changing to an explicit different Org. --- awx/api/serializers.py | 1 + awx/main/access.py | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 22b7ab3a7a..523171e43d 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1362,6 +1362,7 @@ class ProjectOptionsSerializer(BaseSerializer): class ExecutionEnvironmentSerializer(BaseSerializer): show_capabilities = ['edit', 'delete'] + managed_by_tower = serializers.ReadOnlyField() class Meta: model = ExecutionEnvironment diff --git a/awx/main/access.py b/awx/main/access.py index 9e9631751c..7da6709c41 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -1329,29 +1329,31 @@ class ExecutionEnvironmentAccess(BaseAccess): Q(organization__isnull=True) ).distinct() - @check_superuser def can_add(self, data): if not data: # So the browseable API will work return Organization.accessible_objects(self.user, 'execution_environment_admin_role').exists() - return self.check_related('organization', Organization, data, mandatory=True) - - @check_superuser - def can_change(self, obj, data): - if obj.managed_by_tower is True: + if obj.managed_by_tower: raise PermissionDenied + if self.user.is_superuser: + return True + return self.check_related('organization', Organization, data, mandatory=True, + role_field='execution_environment_admin_role') + + def can_change(self, obj, data): + if obj.managed_by_tower: + raise PermissionDenied + if self.user.is_superuser: + return True if obj and obj.organization_id is None: raise PermissionDenied if self.user not in obj.organization.execution_environment_admin_role: raise PermissionDenied - org_pk = get_pk_from_dict(data, 'organization') - if obj and obj.organization_id != org_pk: - # Prevent moving an EE to a different organization, unless a superuser or admin on both orgs. - if obj.organization_id is None or org_pk is None: - raise PermissionDenied - if self.user not in Organization.objects.get(id=org_pk).execution_environment_admin_role: - raise PermissionDenied - - return True + if data and 'organization' in data: + new_org = get_object_from_data('organization', Organization, data, obj=obj) + if not new_org or self.user not in new_org.execution_environment_admin_role: + return False + return self.check_related('organization', Organization, data, obj=obj, mandatory=True, + role_field='execution_environment_admin_role') def can_delete(self, obj): return self.can_change(obj, None)