mirror of
https://github.com/ansible/awx.git
synced 2026-07-25 23:28:15 -02:30
AAP-83163 — Eliminate LEFT JOIN fan-out in user list RBAC query (#16546)
Replace legacy Role M2M traversal in UserAccess.filtered_queryset() with DAB's visible_users(), which queries organizational membership through RoleUserAssignment subqueries instead of LEFT OUTER JOINs through the objectrole/roleevaluation tables. Also replace role__in=actor.has_roles.all() in can_admin() with RoleEvaluation._actor_role_filter() to avoid the objectrole JOIN in per-object permission checks. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ from rest_framework.exceptions import ParseError, PermissionDenied
|
|||||||
# django-ansible-base
|
# django-ansible-base
|
||||||
from ansible_base.lib.utils.validation import to_python_boolean
|
from ansible_base.lib.utils.validation import to_python_boolean
|
||||||
from ansible_base.rbac.models import RoleEvaluation
|
from ansible_base.rbac.models import RoleEvaluation
|
||||||
|
from ansible_base.rbac.policies import visible_users
|
||||||
from ansible_base.rbac import permission_registry
|
from ansible_base.rbac import permission_registry
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
@@ -643,6 +644,8 @@ class UserAccess(BaseAccess):
|
|||||||
Organization.access_qs(self.user, 'change').exists() or Organization.access_qs(self.user, 'audit').exists()
|
Organization.access_qs(self.user, 'change').exists() or Organization.access_qs(self.user, 'audit').exists()
|
||||||
):
|
):
|
||||||
qs = User.objects.all()
|
qs = User.objects.all()
|
||||||
|
elif settings.ANSIBLE_BASE_ROLE_SYSTEM_ACTIVATED:
|
||||||
|
qs = visible_users(self.user)
|
||||||
else:
|
else:
|
||||||
qs = (
|
qs = (
|
||||||
User.objects.filter(pk__in=Organization.access_qs(self.user, 'view').values('member_role__members'))
|
User.objects.filter(pk__in=Organization.access_qs(self.user, 'view').values('member_role__members'))
|
||||||
@@ -706,12 +709,13 @@ class UserAccess(BaseAccess):
|
|||||||
# in these cases only superusers can modify orphan users
|
# in these cases only superusers can modify orphan users
|
||||||
return False
|
return False
|
||||||
if settings.ANSIBLE_BASE_ROLE_SYSTEM_ACTIVATED:
|
if settings.ANSIBLE_BASE_ROLE_SYSTEM_ACTIVATED:
|
||||||
# Permission granted if the user has all permissions that the target user has
|
|
||||||
target_perms = set(
|
target_perms = set(
|
||||||
RoleEvaluation.objects.filter(role__in=obj.has_roles.all()).values_list('object_id', 'content_type_id', 'codename').distinct()
|
RoleEvaluation.objects.filter(**RoleEvaluation._actor_role_filter(obj)).values_list('object_id', 'content_type_id', 'codename').distinct()
|
||||||
)
|
)
|
||||||
user_perms = set(
|
user_perms = set(
|
||||||
RoleEvaluation.objects.filter(role__in=self.user.has_roles.all()).values_list('object_id', 'content_type_id', 'codename').distinct()
|
RoleEvaluation.objects.filter(**RoleEvaluation._actor_role_filter(self.user))
|
||||||
|
.values_list('object_id', 'content_type_id', 'codename')
|
||||||
|
.distinct()
|
||||||
)
|
)
|
||||||
return not (target_perms - user_perms)
|
return not (target_perms - user_perms)
|
||||||
return not obj.roles.all().exclude(ancestors__in=self.user.roles.all()).exists()
|
return not obj.roles.all().exclude(ancestors__in=self.user.roles.all()).exists()
|
||||||
|
|||||||
Reference in New Issue
Block a user