From 300020df0711670305e7ceb463d14770935bfbb0 Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Wed, 10 Aug 2016 14:33:25 -0400 Subject: [PATCH 1/3] Make system admin and system auditor visible to oprhaned users. --- awx/main/models/rbac.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 3cb016ffde..8592a9c632 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -376,12 +376,13 @@ class Role(models.Model): @staticmethod @check_singleton - def visible_roles(user): + def visible_roles(user, include_super=True): sql_params = { 'ancestors_table': Role.ancestors.through._meta.db_table, 'parents_table': Role.parents.through._meta.db_table, 'roles_table': Role._meta.db_table, - 'ids': ','.join(str(x) for x in user.roles.values_list('id', flat=True)) + 'ids': ','.join(str(x) for x in user.roles.values_list('id', flat=True)), + 'mandatories': ','.join(('\'system_administrator\'', '\'system_auditor\'')), } qs = Role.objects.extra( @@ -394,6 +395,17 @@ class Role(models.Model): ) ''' % sql_params] ) + if include_super: + super_qs = Role.objects.extra( + where = [''' + %(roles_table)s.id IN ( + SELECT DISTINCT visible_roles_t3.id + FROM %(roles_table)s as visible_roles_t3 + WHERE visible_roles_t3.singleton_name IN (%(mandatories)s) + ) + ''' % sql_params] + ) + qs = qs | super_qs return qs @staticmethod From b719b7276f34873e4d43958651ea0e2bd1d6e7ba Mon Sep 17 00:00:00 2001 From: jangsutsr Date: Sun, 14 Aug 2016 20:10:45 -0400 Subject: [PATCH 2/3] Refactor for better performance. --- awx/api/views.py | 11 ++++++++++- awx/main/models/rbac.py | 14 +------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/awx/api/views.py b/awx/api/views.py index efbbecf10e..189d687222 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -3830,7 +3830,16 @@ class RoleList(ListAPIView): new_in_300 = True def get_queryset(self): - return Role.visible_roles(self.request.user) + result = Role.visible_roles(self.request.user) + # Sanity check: is the requesting user an orphaned non-admin/auditor? + # if yes, make system admin/auditor mandatorily visible. + if not self.request.user.organizations.exists() and\ + not self.request.user.is_superuser and\ + not self.request.user.is_system_auditor: + mandatories = ('system_administrator', 'system_auditor') + super_qs = Role.objects.filter(singleton_name__in=mandatories) + result = result | super_qs + return result class RoleDetail(RetrieveAPIView): diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 8592a9c632..f469c1a7ac 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -376,13 +376,12 @@ class Role(models.Model): @staticmethod @check_singleton - def visible_roles(user, include_super=True): + def visible_roles(user): sql_params = { 'ancestors_table': Role.ancestors.through._meta.db_table, 'parents_table': Role.parents.through._meta.db_table, 'roles_table': Role._meta.db_table, 'ids': ','.join(str(x) for x in user.roles.values_list('id', flat=True)), - 'mandatories': ','.join(('\'system_administrator\'', '\'system_auditor\'')), } qs = Role.objects.extra( @@ -395,17 +394,6 @@ class Role(models.Model): ) ''' % sql_params] ) - if include_super: - super_qs = Role.objects.extra( - where = [''' - %(roles_table)s.id IN ( - SELECT DISTINCT visible_roles_t3.id - FROM %(roles_table)s as visible_roles_t3 - WHERE visible_roles_t3.singleton_name IN (%(mandatories)s) - ) - ''' % sql_params] - ) - qs = qs | super_qs return qs @staticmethod From 89cbceeab88dad7b35f43f7b9c8c5f136e15b379 Mon Sep 17 00:00:00 2001 From: Aaron Tan Date: Tue, 20 Sep 2016 11:39:44 -0400 Subject: [PATCH 3/3] Functional test added. --- awx/main/tests/functional/api/test_role.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 awx/main/tests/functional/api/test_role.py diff --git a/awx/main/tests/functional/api/test_role.py b/awx/main/tests/functional/api/test_role.py new file mode 100644 index 0000000000..94215521a5 --- /dev/null +++ b/awx/main/tests/functional/api/test_role.py @@ -0,0 +1,13 @@ +import pytest + +from django.core.urlresolvers import reverse + +@pytest.mark.django_db +def test_admin_visible_to_orphaned_users(get, alice): + names = set() + + response = get(reverse('api:role_list'), user=alice) + for item in response.data['results']: + names.add(item['name']) + assert 'System Auditor' in names + assert 'System Administrator' in names