diff --git a/awx/api/views.py b/awx/api/views.py index 6bd917cab2..1cb44f3c60 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -3786,6 +3786,11 @@ class RoleTeamsList(ListAPIView): # XXX: Need to pull in can_attach and can_unattach kinda code from SubListCreateAttachDetachAPIView role = Role.objects.get(pk=self.kwargs['pk']) team = Team.objects.get(pk=sub_id) + from awx.main.access import RoleAccess + access = RoleAccess(request.user) + if access.can_attach(role, team, 'members', {"id": role.pk}, skip_sub_obj_read_check=False): + raise PermissionDenied() + if request.data.get('disassociate', None): team.member_role.children.remove(role) else: diff --git a/awx/main/tests/functional/test_rbac_role.py b/awx/main/tests/functional/test_rbac_role.py index bb61262fd5..20ab8ed6ba 100644 --- a/awx/main/tests/functional/test_rbac_role.py +++ b/awx/main/tests/functional/test_rbac_role.py @@ -11,17 +11,36 @@ from django.contrib.auth.models import User @pytest.mark.django_db -def test_inventory_read_role_access_functional(rando, inventory, mocker, post): +def test_user_role_access_view(rando, inventory, mocker, post): + # rando has read access for the inventory inventory.read_role.members.add(rando) - role_pk = inventory.admin_role.pk - mock_access = mocker.MagicMock(spec=RoleAccess, id=968) + role_pk = inventory.admin_role.pk + mock_access = mocker.MagicMock(spec=RoleAccess, can_attach=mock.MagicMock(return_value=False)) with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access): response = post(url=reverse('api:user_roles_list', args=(rando.pk,)), data={'id': role_pk}, user=rando) mock_access.can_attach.assert_called_once_with( inventory.admin_role, rando, 'members', {"id": role_pk}, skip_sub_obj_read_check=False) + assert rando not in inventory.admin_role + +@pytest.mark.django_db +def test_role_team_access_view(rando, team, inventory, mocker, post): + # rando is admin of the team + team.admin_role.members.add(rando) + # team has read_role for the inventory + team.member_role.children.add(inventory.read_role) + + role_pk = inventory.admin_role.pk + mock_access = mocker.MagicMock(spec=RoleAccess) + with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access): + response = post(url=reverse('api:role_teams_list', args=(role_pk,)), + data={'id': team.pk}, user=rando) + mock_access.can_attach.assert_called_once_with( + inventory.admin_role, team, 'members', {"id": role_pk}, + skip_sub_obj_read_check=False) + assert team not in inventory.admin_role @pytest.mark.django_db def test_inventory_read_role_user_can_access(rando, inventory):