diff --git a/awx/main/access.py b/awx/main/access.py index 1de1e8fb3f..ddecce39e2 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -2396,6 +2396,14 @@ class RoleAccess(BaseAccess): if not check_user_access(self.user, sub_obj_resource.__class__, 'read', sub_obj_resource): return False + # Being a user in the member_role or admin_role of an organization grants + # administrators of that Organization the ability to edit that user. To prevent + # unwanted escalations lets ensure that the Organization administartor has the abilty + # to admin the user being added to the role. + if isinstance(obj.content_object, Organization) and obj.role_field in ['member_role', 'admin_role']: + if not UserAccess(self.user).can_admin(sub_obj, None): + return False + if isinstance(obj.content_object, ResourceMixin) and \ self.user in obj.content_object.admin_role: return True diff --git a/awx/main/tests/functional/test_rbac_role.py b/awx/main/tests/functional/test_rbac_role.py index 16ad46f8db..62b8469abf 100644 --- a/awx/main/tests/functional/test_rbac_role.py +++ b/awx/main/tests/functional/test_rbac_role.py @@ -32,3 +32,15 @@ def test_role_access_attach(rando, inventory): inventory.read_role.members.add(rando) access = RoleAccess(rando) assert not access.can_attach(inventory.admin_role, rando, 'members', None) + + +@pytest.mark.django_db +def test_org_user_role_attach(user, organization): + admin = user('admin') + nonmember = user('nonmember') + + organization.admin_role.members.add(admin) + + access = RoleAccess(admin) + assert not access.can_attach(organization.member_role, nonmember, 'members', None) + assert not access.can_attach(organization.admin_role, nonmember, 'members', None)