diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 299a34e554..ca454a0b1e 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1265,6 +1265,20 @@ class OrganizationSerializer(BaseSerializer): summary_dict['related_field_counts'] = counts_dict[obj.id] return summary_dict + def validate(self, attrs): + obj = self.instance + view = self.context['view'] + + obj_limit = getattr(obj, 'max_hosts', None) + api_limit = attrs.get('max_hosts') + + if not view.request.user.is_superuser: + if api_limit is not None and api_limit != obj_limit: + # Only allow superusers to edit the max_hosts field + raise serializers.ValidationError(_('Cannot change max_hosts.')) + + return super(OrganizationSerializer, self).validate(attrs) + class ProjectOptionsSerializer(BaseSerializer): diff --git a/awx/main/tests/functional/api/test_organizations.py b/awx/main/tests/functional/api/test_organizations.py index c1fa99e810..18aeb269ac 100644 --- a/awx/main/tests/functional/api/test_organizations.py +++ b/awx/main/tests/functional/api/test_organizations.py @@ -199,6 +199,30 @@ def test_update_organization(get, put, organization, alice, bob): put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=bob, expect=403) +@pytest.mark.django_db +def test_update_organization_max_hosts(get, put, organization, admin, alice, bob): + # Admin users can get and update max_hosts + data = get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=admin, expect=200).data + assert organization.max_hosts == 0 + data['max_hosts'] = 3 + put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=admin, expect=200) + organization.refresh_from_db() + assert organization.max_hosts == 3 + + # Organization admins can get the data and can update other fields, but not max_hosts + organization.admin_role.members.add(alice) + data = get(reverse('api:organization_detail', kwargs={'pk': organization.id}), user=alice, expect=200).data + data['max_hosts'] = 5 + put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=alice, expect=400) + organization.refresh_from_db() + assert organization.max_hosts == 3 + + # Ordinary users shouldn't be able to update either. + put(reverse('api:organization_detail', kwargs={'pk': organization.id}), data, user=bob, expect=403) + organization.refresh_from_db() + assert organization.max_hosts == 3 + + @pytest.mark.django_db @mock.patch('awx.main.access.BaseAccess.check_license', lambda *a, **kw: True) def test_delete_organization(delete, organization, admin):