Merge pull request #2583 from AlanCoding/superusers_manage

Do not block superusers with MANAGE_ORGANIZATION_AUTH setting

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot]
2018-11-07 17:38:04 +00:00
committed by GitHub
2 changed files with 61 additions and 15 deletions

View File

@@ -524,7 +524,7 @@ class UserAccess(BaseAccess):
# A user can be changed if they are themselves, or by org admins or # A user can be changed if they are themselves, or by org admins or
# superusers. Change permission implies changing only certain fields # superusers. Change permission implies changing only certain fields
# that a user should be able to edit for themselves. # that a user should be able to edit for themselves.
if not settings.MANAGE_ORGANIZATION_AUTH: if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False return False
return bool(self.user == obj or self.can_admin(obj, data)) return bool(self.user == obj or self.can_admin(obj, data))
@@ -577,7 +577,7 @@ class UserAccess(BaseAccess):
return False return False
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs): def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
if not settings.MANAGE_ORGANIZATION_AUTH: if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False return False
# Reverse obj and sub_obj, defer to RoleAccess if this is a role assignment. # Reverse obj and sub_obj, defer to RoleAccess if this is a role assignment.
@@ -587,7 +587,7 @@ class UserAccess(BaseAccess):
return super(UserAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs) return super(UserAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs)
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs): def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
if not settings.MANAGE_ORGANIZATION_AUTH: if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False return False
if relationship == 'roles': if relationship == 'roles':
@@ -1157,13 +1157,10 @@ class TeamAccess(BaseAccess):
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs): def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
"""Reverse obj and sub_obj, defer to RoleAccess if this is an assignment """Reverse obj and sub_obj, defer to RoleAccess if this is an assignment
of a resource role to the team.""" of a resource role to the team."""
if not settings.MANAGE_ORGANIZATION_AUTH: # MANAGE_ORGANIZATION_AUTH setting checked in RoleAccess
return False
if isinstance(sub_obj, Role): if isinstance(sub_obj, Role):
if sub_obj.content_object is None: if sub_obj.content_object is None:
raise PermissionDenied(_("The {} role cannot be assigned to a team").format(sub_obj.name)) raise PermissionDenied(_("The {} role cannot be assigned to a team").format(sub_obj.name))
elif isinstance(sub_obj.content_object, User):
raise PermissionDenied(_("The admin_role for a User cannot be assigned to a team"))
if isinstance(sub_obj.content_object, ResourceMixin): if isinstance(sub_obj.content_object, ResourceMixin):
role_access = RoleAccess(self.user) role_access = RoleAccess(self.user)
@@ -1175,9 +1172,7 @@ class TeamAccess(BaseAccess):
*args, **kwargs) *args, **kwargs)
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs): def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
if not settings.MANAGE_ORGANIZATION_AUTH: # MANAGE_ORGANIZATION_AUTH setting checked in RoleAccess
return False
if isinstance(sub_obj, Role): if isinstance(sub_obj, Role):
if isinstance(sub_obj.content_object, ResourceMixin): if isinstance(sub_obj.content_object, ResourceMixin):
role_access = RoleAccess(self.user) role_access = RoleAccess(self.user)
@@ -2552,14 +2547,13 @@ class RoleAccess(BaseAccess):
# Unsupported for now # Unsupported for now
return False return False
def can_attach(self, obj, sub_obj, relationship, data, def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
skip_sub_obj_read_check=False): return self.can_unattach(obj, sub_obj, relationship, *args, **kwargs)
return self.can_unattach(obj, sub_obj, relationship, data, skip_sub_obj_read_check)
@check_superuser @check_superuser
def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False): def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False):
if isinstance(obj.content_object, Team): if isinstance(obj.content_object, Team):
if not settings.MANAGE_ORGANIZATION_AUTH: if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False return False
if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents', 'parents']: if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents', 'parents']:

View File

@@ -1,8 +1,9 @@
import pytest import pytest
import mock
from django.test import TransactionTestCase from django.test import TransactionTestCase
from awx.main.access import UserAccess from awx.main.access import UserAccess, RoleAccess, TeamAccess
from awx.main.models import User, Organization, Inventory from awx.main.models import User, Organization, Inventory
@@ -59,6 +60,57 @@ def test_user_queryset(user):
assert qs.count() == 1 assert qs.count() == 1
@pytest.mark.django_db
@pytest.mark.parametrize('ext_auth,superuser,expect', [
(True, True, True),
(False, True, True), # your setting can't touch me, I'm superuser
(True, False, True), # org admin, managing my peeps
(False, False, False), # setting blocks org admin
], ids=['superuser', 'superuser-off', 'org', 'org-off'])
def test_manage_org_auth_setting(ext_auth, superuser, expect, organization, rando, user, team):
u = user('foo-user', is_superuser=superuser)
if not superuser:
organization.admin_role.members.add(u)
with mock.patch('awx.main.access.settings') as settings_mock:
settings_mock.MANAGE_ORGANIZATION_AUTH = ext_auth
assert [
# use via /api/v2/users/N/roles/
UserAccess(u).can_attach(rando, organization.admin_role, 'roles'),
UserAccess(u).can_attach(rando, team.admin_role, 'roles'),
# use via /api/v2/roles/N/users/
RoleAccess(u).can_attach(organization.admin_role, rando, 'members'),
RoleAccess(u).can_attach(team.admin_role, rando, 'members')
] == [expect for i in range(4)]
assert [
# use via /api/v2/users/N/roles/
UserAccess(u).can_unattach(rando, organization.admin_role, 'roles'),
UserAccess(u).can_unattach(rando, team.admin_role, 'roles'),
# use via /api/v2/roles/N/users/
RoleAccess(u).can_unattach(organization.admin_role, rando, 'members'),
RoleAccess(u).can_unattach(team.admin_role, rando, 'members')
] == [expect for i in range(4)]
@pytest.mark.django_db
@pytest.mark.parametrize('ext_auth', [True, False])
def test_team_org_resource_role(ext_auth, organization, rando, org_admin, team):
with mock.patch('awx.main.access.settings') as settings_mock:
settings_mock.MANAGE_ORGANIZATION_AUTH = ext_auth
assert [
# use via /api/v2/teams/N/roles/
TeamAccess(org_admin).can_attach(team, organization.workflow_admin_role, 'roles'),
# use via /api/v2/roles/teams/
RoleAccess(org_admin).can_attach(organization.workflow_admin_role, team, 'member_role.parents')
] == [True for i in range(2)]
assert [
# use via /api/v2/teams/N/roles/
TeamAccess(org_admin).can_unattach(team, organization.workflow_admin_role, 'roles'),
# use via /api/v2/roles/teams/
RoleAccess(org_admin).can_unattach(organization.workflow_admin_role, team, 'member_role.parents')
] == [True for i in range(2)]
@pytest.mark.django_db @pytest.mark.django_db
def test_user_accessible_objects(user, organization): def test_user_accessible_objects(user, organization):
''' '''