diff --git a/awx/main/access.py b/awx/main/access.py index fc89a3487f..510bc814d1 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -881,7 +881,7 @@ class SystemJobAccess(BaseAccess): ''' model = SystemJob -class AdHocCommandAccess(BaseAccess): +class AdHocCommandAccess(BaseAccess): ''' I can only see/run ad hoc commands when: - I am a superuser. @@ -1193,15 +1193,39 @@ class NotificationAccess(BaseAccess): class LabelAccess(BaseAccess): ''' - I can see/use a Label if I have permission to + I can see/use a Label if I have permission to associated organization ''' model = Label def get_queryset(self): - return self.model.objects.distinct().all() + if self.user.is_superuser: + return self.model.objects.all() + return self.model.objects.filter( + organization__in=Organization.accessible_objects(self.user, {'read': True}) + ) + + def can_read(self, obj): + if self.user.is_superuser: + return True + return obj.organization and obj.organization.accessible_by(self.user, {'read': True}) + + def can_add(self, data): + if self.user.is_superuser: + return True + if not data or '_method' in data: # So the browseable API will work? + return True + + org_pk = get_pk_from_dict(data, 'organization') + org = get_object_or_400(Organization, pk=org_pk) + return org.accessible_by(self.user, {'read': True}) + + def can_change(self, obj, data): + if self.user.is_superuser: + return True + return obj.organization and obj.organization.accessible_by(self.user, ALL_PERMISSIONS) def can_delete(self, obj): - return False + return self.can_change(obj, None) class ActivityStreamAccess(BaseAccess): ''' diff --git a/awx/main/tests/functional/conftest.py b/awx/main/tests/functional/conftest.py index 405f3fa0e8..11616f2e69 100644 --- a/awx/main/tests/functional/conftest.py +++ b/awx/main/tests/functional/conftest.py @@ -151,6 +151,10 @@ def credential(): def inventory(organization): return organization.inventories.create(name="test-inv") +@pytest.fixture +def label(organization): + return organization.labels.create(name="test-label", description="test-label-desc") + @pytest.fixture def role(): return Role.objects.create(name='role') @@ -219,9 +223,6 @@ def hosts(group): return hosts return rf - - - @pytest.fixture def permissions(): return { diff --git a/awx/main/tests/functional/test_rbac_label.py b/awx/main/tests/functional/test_rbac_label.py new file mode 100644 index 0000000000..62d28dbe84 --- /dev/null +++ b/awx/main/tests/functional/test_rbac_label.py @@ -0,0 +1,50 @@ +import pytest + +from awx.main.access import ( + LabelAccess, +) + +@pytest.mark.django_db +def test_label_get_queryset_user(label, user): + access = LabelAccess(user('user', False)) + label.organization.member_role.members.add(user('user', False)) + assert access.get_queryset().count() == 1 + +@pytest.mark.django_db +def test_label_get_queryset_su(label, user): + access = LabelAccess(user('user', True)) + assert access.get_queryset().count() == 1 + +@pytest.mark.django_db +def test_label_access(label, user): + access = LabelAccess(user('user', False)) + assert not access.can_read(label) + +@pytest.mark.django_db +def test_label_access_superuser(label, user): + access = LabelAccess(user('admin', True)) + + assert access.can_read(label) + assert access.can_change(label, None) + assert access.can_delete(label) + +@pytest.mark.django_db +def test_label_access_admin(label, user): + '''can_change because I am an admin of that org''' + a = user('admin', False) + label.organization.admin_role.members.add(a) + + access = LabelAccess(user('admin', False)) + assert access.can_read(label) + assert access.can_change(label, None) + assert access.can_delete(label) + +@pytest.mark.django_db +def test_label_access_user(label, user): + access = LabelAccess(user('user', False)) + label.organization.member_role.members.add(user('user', False)) + + assert access.can_read(label) + assert not access.can_change(label, None) + assert not access.can_delete(label) +