mirror of
https://github.com/ansible/awx.git
synced 2026-05-12 11:57:37 -02:30
TeamRolesList permission tests and fix, organize tests
This commit is contained in:
@@ -3783,22 +3783,22 @@ class RoleTeamsList(ListAPIView):
|
|||||||
if not sub_id:
|
if not sub_id:
|
||||||
data = dict(msg="Role 'id' field is missing.")
|
data = dict(msg="Role 'id' field is missing.")
|
||||||
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
return Response(data, status=status.HTTP_400_BAD_REQUEST)
|
||||||
# XXX: Need to pull in can_attach and can_unattach kinda code from SubListCreateAttachDetachAPIView
|
|
||||||
role = Role.objects.get(pk=self.kwargs['pk'])
|
role = Role.objects.get(pk=self.kwargs['pk'])
|
||||||
team = Team.objects.get(pk=sub_id)
|
team = Team.objects.get(pk=sub_id)
|
||||||
from awx.main.access import RoleAccess
|
action = 'attach'
|
||||||
access = RoleAccess(request.user)
|
if request.data.get('disassociate', None):
|
||||||
if access.can_attach(role, team, 'members', {"id": role.pk}, skip_sub_obj_read_check=False):
|
action = 'unattach'
|
||||||
|
if not request.user.can_access(self.parent_model, action, role, team,
|
||||||
|
self.relationship, request.data,
|
||||||
|
skip_sub_obj_read_check=False):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
if request.data.get('disassociate', None):
|
if request.data.get('disassociate', None):
|
||||||
team.member_role.children.remove(role)
|
team.member_role.children.remove(role)
|
||||||
else:
|
else:
|
||||||
team.member_role.children.add(role)
|
team.member_role.children.add(role)
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
# XXX attach/detach needs to ensure we have the appropriate perms
|
|
||||||
|
|
||||||
|
|
||||||
class RoleParentsList(SubListAPIView):
|
class RoleParentsList(SubListAPIView):
|
||||||
|
|
||||||
|
|||||||
@@ -270,11 +270,18 @@ class UserAccess(BaseAccess):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def can_attach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
|
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
|
||||||
|
"Reverse obj and sub_obj, defer to RoleAccess if this is a role assignment."
|
||||||
if relationship == 'roles':
|
if relationship == 'roles':
|
||||||
role_access = RoleAccess(self.user)
|
role_access = RoleAccess(self.user)
|
||||||
return role_access.can_attach(sub_obj, obj, 'members', data, skip_sub_obj_read_check=False)
|
return role_access.can_attach(sub_obj, obj, 'members', *args, **kwargs)
|
||||||
return super(UserAccess, self).can_attach(obj, sub_obj, relationship, data, skip_sub_obj_read_check=False)
|
return super(UserAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs)
|
||||||
|
|
||||||
|
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
|
||||||
|
if relationship == 'roles':
|
||||||
|
role_access = RoleAccess(self.user)
|
||||||
|
return role_access.can_unattach(sub_obj, obj, 'members', *args, **kwargs)
|
||||||
|
return super(UserAccess, self).can_unattach(obj, sub_obj, relationship, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class OrganizationAccess(BaseAccess):
|
class OrganizationAccess(BaseAccess):
|
||||||
@@ -652,6 +659,23 @@ class TeamAccess(BaseAccess):
|
|||||||
def can_delete(self, obj):
|
def can_delete(self, obj):
|
||||||
return self.can_change(obj, None)
|
return self.can_change(obj, None)
|
||||||
|
|
||||||
|
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
|
||||||
|
"Reverse obj and sub_obj, defer to RoleAccess if this is a role assignment."
|
||||||
|
if relationship == 'member_role.children':
|
||||||
|
role_access = RoleAccess(self.user)
|
||||||
|
return role_access.can_attach(sub_obj, obj, 'member_role.parents',
|
||||||
|
*args, **kwargs)
|
||||||
|
return super(TeamAccess, self).can_attach(obj, sub_obj, relationship,
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
|
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
|
||||||
|
if relationship == 'member_role.children':
|
||||||
|
role_access = RoleAccess(self.user)
|
||||||
|
return role_access.can_unattach(sub_obj, obj, 'member_role.parents',
|
||||||
|
*args, **kwargs)
|
||||||
|
return super(TeamAccess, self).can_unattach(obj, sub_obj, relationship,
|
||||||
|
*args, **kwargs)
|
||||||
|
|
||||||
class ProjectAccess(BaseAccess):
|
class ProjectAccess(BaseAccess):
|
||||||
'''
|
'''
|
||||||
I can see projects when:
|
I can see projects when:
|
||||||
|
|||||||
48
awx/main/tests/functional/api/test_create_attach_views.py
Normal file
48
awx/main/tests/functional/api/test_create_attach_views.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_user_role_view_access(rando, inventory, mocker, post):
|
||||||
|
"Assure correct access method is called when assigning users new roles"
|
||||||
|
role_pk = inventory.admin_role.pk
|
||||||
|
data = {"id": role_pk}
|
||||||
|
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
||||||
|
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
||||||
|
post(url=reverse('api:user_roles_list', args=(rando.pk,)),
|
||||||
|
data=data, user=rando, expect=403)
|
||||||
|
mock_access.can_attach.assert_called_once_with(
|
||||||
|
inventory.admin_role, rando, 'members', data,
|
||||||
|
skip_sub_obj_read_check=False)
|
||||||
|
assert rando not in inventory.admin_role
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_team_role_view_access(rando, team, inventory, mocker, post):
|
||||||
|
"Assure correct access method is called when assigning teams new roles"
|
||||||
|
team.admin_role.members.add(rando)
|
||||||
|
role_pk = inventory.admin_role.pk
|
||||||
|
data = {"id": role_pk}
|
||||||
|
mock_access = mocker.MagicMock(can_attach=mocker.MagicMock(return_value=False))
|
||||||
|
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
||||||
|
post(url=reverse('api:team_roles_list', args=(team.pk,)),
|
||||||
|
data=data, user=rando, expect=403)
|
||||||
|
mock_access.can_attach.assert_called_once_with(
|
||||||
|
inventory.admin_role, team, 'member_role.parents', data,
|
||||||
|
skip_sub_obj_read_check=False)
|
||||||
|
assert team not in inventory.admin_role
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_role_team_view_access(rando, team, inventory, mocker, post):
|
||||||
|
"""Assure that /role/N/teams/ enforces the same permission restrictions
|
||||||
|
that /teams/N/roles/ does when assigning teams new roles"""
|
||||||
|
role_pk = inventory.admin_role.pk
|
||||||
|
data = {"id": team.pk}
|
||||||
|
mock_access = mocker.MagicMock(return_value=False, __name__='mocked')
|
||||||
|
with mocker.patch('awx.main.access.RoleAccess.can_attach', mock_access):
|
||||||
|
post(url=reverse('api:role_teams_list', args=(role_pk,)),
|
||||||
|
data=data, user=rando, expect=403)
|
||||||
|
mock_access.assert_called_once_with(
|
||||||
|
inventory.admin_role, team, 'member_role.parents', data,
|
||||||
|
skip_sub_obj_read_check=False)
|
||||||
|
assert team not in inventory.admin_role
|
||||||
@@ -1,64 +1,32 @@
|
|||||||
import mock
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from awx.main.access import (
|
from awx.main.access import (
|
||||||
RoleAccess,
|
RoleAccess,
|
||||||
UserAccess
|
UserAccess,
|
||||||
)
|
TeamAccess)
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_user_role_access_view(rando, inventory, mocker, post):
|
def test_team_access_attach(rando, team, inventory):
|
||||||
# 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, 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
|
# rando is admin of the team
|
||||||
team.admin_role.members.add(rando)
|
team.admin_role.members.add(rando)
|
||||||
|
inventory.read_role.members.add(rando)
|
||||||
# team has read_role for the inventory
|
# team has read_role for the inventory
|
||||||
team.member_role.children.add(inventory.read_role)
|
team.member_role.children.add(inventory.read_role)
|
||||||
|
|
||||||
role_pk = inventory.admin_role.pk
|
access = TeamAccess(rando)
|
||||||
mock_access = mocker.MagicMock(spec=RoleAccess)
|
data = {'id': inventory.admin_role.pk}
|
||||||
with mocker.patch('awx.main.access.RoleAccess', return_value=mock_access):
|
assert not access.can_attach(team, inventory.admin_role, 'member_role.children', data, False)
|
||||||
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
|
@pytest.mark.django_db
|
||||||
def test_inventory_read_role_user_can_access(rando, inventory):
|
def test_user_access_attach(rando, inventory):
|
||||||
inventory.read_role.members.add(rando)
|
|
||||||
access = RoleAccess(rando)
|
|
||||||
assert not rando.can_access(
|
|
||||||
User, 'attach', rando, inventory.admin_role, 'roles',
|
|
||||||
{'id': inventory.admin_role.pk}, False)
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_inventory_read_role_user_access(rando, inventory):
|
|
||||||
inventory.read_role.members.add(rando)
|
inventory.read_role.members.add(rando)
|
||||||
access = UserAccess(rando)
|
access = UserAccess(rando)
|
||||||
data = {'id': inventory.admin_role.pk}
|
data = {'id': inventory.admin_role.pk}
|
||||||
assert not access.can_attach(rando, inventory.admin_role, 'roles', data, False)
|
assert not access.can_attach(rando, inventory.admin_role, 'roles', data, False)
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_inventory_read_role_access(rando, inventory):
|
def test_role_access_attach(rando, inventory):
|
||||||
inventory.read_role.members.add(rando)
|
inventory.read_role.members.add(rando)
|
||||||
access = RoleAccess(rando)
|
access = RoleAccess(rando)
|
||||||
assert not access.can_attach(inventory.admin_role, rando, 'members', None)
|
assert not access.can_attach(inventory.admin_role, rando, 'members', None)
|
||||||
|
|||||||
Reference in New Issue
Block a user