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.
This commit is contained in:
Jeff Bradberry
2021-02-19 14:06:01 -05:00
committed by Shane McDonald
parent 41fb21911e
commit 5b2adc89cf
2 changed files with 18 additions and 15 deletions

View File

@@ -1362,6 +1362,7 @@ class ProjectOptionsSerializer(BaseSerializer):
class ExecutionEnvironmentSerializer(BaseSerializer): class ExecutionEnvironmentSerializer(BaseSerializer):
show_capabilities = ['edit', 'delete'] show_capabilities = ['edit', 'delete']
managed_by_tower = serializers.ReadOnlyField()
class Meta: class Meta:
model = ExecutionEnvironment model = ExecutionEnvironment

View File

@@ -1329,29 +1329,31 @@ class ExecutionEnvironmentAccess(BaseAccess):
Q(organization__isnull=True) Q(organization__isnull=True)
).distinct() ).distinct()
@check_superuser
def can_add(self, data): def can_add(self, data):
if not data: # So the browseable API will work if not data: # So the browseable API will work
return Organization.accessible_objects(self.user, 'execution_environment_admin_role').exists() return Organization.accessible_objects(self.user, 'execution_environment_admin_role').exists()
return self.check_related('organization', Organization, data, mandatory=True) if obj.managed_by_tower:
@check_superuser
def can_change(self, obj, data):
if obj.managed_by_tower is True:
raise PermissionDenied 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: if obj and obj.organization_id is None:
raise PermissionDenied raise PermissionDenied
if self.user not in obj.organization.execution_environment_admin_role: if self.user not in obj.organization.execution_environment_admin_role:
raise PermissionDenied raise PermissionDenied
org_pk = get_pk_from_dict(data, 'organization') if data and 'organization' in data:
if obj and obj.organization_id != org_pk: new_org = get_object_from_data('organization', Organization, data, obj=obj)
# Prevent moving an EE to a different organization, unless a superuser or admin on both orgs. if not new_org or self.user not in new_org.execution_environment_admin_role:
if obj.organization_id is None or org_pk is None: return False
raise PermissionDenied return self.check_related('organization', Organization, data, obj=obj, mandatory=True,
if self.user not in Organization.objects.get(id=org_pk).execution_environment_admin_role: role_field='execution_environment_admin_role')
raise PermissionDenied
return True
def can_delete(self, obj): def can_delete(self, obj):
return self.can_change(obj, None) return self.can_change(obj, None)