Merge pull request #1265 from anoek/rbac

Various small fixes and progress on making 'old' tests work again on RBAC
This commit is contained in:
Wayne Witzel III 2016-03-18 11:21:10 -04:00
commit 8a1f21de12
16 changed files with 121 additions and 344 deletions

View File

@ -299,7 +299,7 @@ class SubListAPIView(ListAPIView, ParentMixin):
parent = self.get_parent_object()
self.check_parent_access(parent)
qs = self.request.user.get_queryset(self.model).distinct()
sublist_qs = getattr(parent, self.relationship).distinct()
sublist_qs = getattrd(parent, self.relationship).distinct()
return qs & sublist_qs
class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):

View File

@ -117,6 +117,7 @@ class ModelAccessPermission(permissions.BasePermission):
check_method = getattr(self, 'check_%s_permissions' % request.method.lower(), None)
result = check_method and check_method(request, view, obj)
if not result:
print('Yarr permission denied: %s %s %s' % (request.method, repr(view), repr(obj),)) # TODO: XXX: This shouldn't have been committed but anoek is sloppy, remove me after we're done fixing bugs
raise PermissionDenied()
return result

View File

@ -274,7 +274,6 @@ v1_urls = patterns('awx.api.views',
url(r'^me/$', 'user_me_list'),
url(r'^dashboard/$', 'dashboard_view'),
url(r'^dashboard/graphs/jobs/$', 'dashboard_jobs_graph_view'),
url(r'^dashboard/graphs/inventory/$', 'dashboard_inventory_graph_view'),
url(r'^settings/', include(settings_urls)),
url(r'^schedules/', include(schedule_urls)),
url(r'^organizations/', include(organization_urls)),

View File

@ -288,8 +288,7 @@ class DashboardView(APIView):
def get(self, request, format=None):
''' Show Dashboard Details '''
data = OrderedDict()
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view'),
'inventory_graph': reverse('api:dashboard_inventory_graph_view')}
data['related'] = {'jobs_graph': reverse('api:dashboard_jobs_graph_view')}
user_inventory = get_user_queryset(request.user, Inventory)
inventory_with_failed_hosts = user_inventory.filter(hosts_with_active_failures__gt=0)
user_inventory_external = user_inventory.filter(has_inventory_sources=True)
@ -435,49 +434,6 @@ class DashboardJobsGraphView(APIView):
element[1]])
return Response(dashboard_data)
class DashboardInventoryGraphView(APIView):
view_name = "Dashboard Inventory Graphs"
new_in_200 = True
def get(self, request, format=None):
period = request.query_params.get('period', 'month')
end_date = now()
if period == 'month':
start_date = end_date - dateutil.relativedelta.relativedelta(months=1)
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
delta = dateutil.relativedelta.relativedelta(days=1)
elif period == 'week':
start_date = end_date - dateutil.relativedelta.relativedelta(weeks=1)
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
delta = dateutil.relativedelta.relativedelta(days=1)
elif period == 'day':
start_date = end_date - dateutil.relativedelta.relativedelta(days=1)
start_date = start_date.replace(minute=0, second=0, microsecond=0)
delta = dateutil.relativedelta.relativedelta(hours=1)
else:
raise ParseError(u'Unknown period "%s"' % force_text(period))
host_stats = []
date = start_date
while date < end_date:
next_date = date + delta
# Find all hosts that existed at end of intevral that are still
# active or were deleted after the end of interval. Slow but
# accurate; haven't yet found a better way to do it.
hosts_qs = Host.objects.filter(created__lt=next_date)
hosts_qs = hosts_qs.filter(Q(active=True) | Q(active=False, modified__gte=next_date))
hostnames = set()
for name, active in hosts_qs.values_list('name', 'active').iterator():
if not active:
name = re.sub(r'^_deleted_.*?_', '', name)
hostnames.add(name)
host_stats.append((time.mktime(date.timetuple()), len(hostnames)))
date = next_date
return Response({'hosts': host_stats})
class ScheduleList(ListAPIView):
@ -633,16 +589,16 @@ class OrganizationUsersList(SubListCreateAttachDetachAPIView):
model = User
serializer_class = UserSerializer
parent_model = Organization
relationship = 'users'
relationship = 'member_role.members'
class OrganizationAdminsList(SubListCreateAttachDetachAPIView):
model = User
serializer_class = UserSerializer
parent_model = Organization
relationship = 'admins'
relationship = 'admin_role.members'
class OrganizationProjectsList(SubListCreateAttachDetachAPIView):
class OrganizationProjectsList(SubListCreateAPIView):
model = Project
serializer_class = ProjectSerializer
@ -725,7 +681,7 @@ class TeamUsersList(SubListCreateAttachDetachAPIView):
model = User
serializer_class = UserSerializer
parent_model = Team
relationship = 'users'
relationship = 'member_role.members'
class TeamRolesList(SubListCreateAttachDetachAPIView):
@ -1481,7 +1437,7 @@ class GroupAllHostsList(SubListAPIView):
def get_queryset(self):
parent = self.get_parent_object()
self.check_parent_access(parent)
qs = self.request.user.get_queryset(self.model)
qs = self.request.user.get_queryset(self.model).distinct() # need distinct for '&' operator
sublist_qs = parent.all_hosts.distinct()
return qs & sublist_qs

View File

@ -7,10 +7,9 @@ import sys
import logging
# Django
from django.db.models import F, Q
from django.db.models import Q
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models.aggregates import Max
# Django REST Framework
from rest_framework.exceptions import ParseError, PermissionDenied
@ -67,15 +66,7 @@ def user_admin_role(self):
return Role.objects.get(content_type=ContentType.objects.get_for_model(User), object_id=self.id)
def user_accessible_objects(user, permissions):
content_type = ContentType.objects.get_for_model(User)
qs = RolePermission.objects.filter(
content_type=content_type,
role__ancestors__members=user
)
for perm in permissions:
qs = qs.annotate(**{'max_' + perm: Max(perm)})
qs = qs.filter(**{'max_' + perm: int(permissions[perm])})
return qs
return ResourceMixin._accessible_objects(User, user, permissions)
def user_accessible_by(instance, user, permissions):
perms = get_user_permissions_on_resource(instance, user)
@ -222,7 +213,7 @@ class UserAccess(BaseAccess):
model = User
def get_queryset(self):
qs = self.model.accessible_objects(self.user, {'read':True})
qs = User.accessible_objects(self.user, {'read':True})
return qs
def can_add(self, data):
@ -639,7 +630,7 @@ class ProjectAccess(BaseAccess):
def can_add(self, data):
if self.user.is_superuser:
return True
qs = Organization.accessible_objects(self.uesr, ALL_PERMISSIONS)
qs = Organization.accessible_objects(self.user, ALL_PERMISSIONS)
return bool(qs.count() > 0)
def can_change(self, obj, data):
@ -813,47 +804,11 @@ class JobAccess(BaseAccess):
qs = qs.prefetch_related('unified_job_template')
if self.user.is_superuser:
return qs
credential_ids = self.user.get_queryset(Credential)
base_qs = qs.filter(
return qs.filter(
credential_id__in=credential_ids,
)
org_admin_ids = base_qs.filter(
Q(project__organizations__admins__in=[self.user]) |
(Q(project__isnull=True) & Q(job_type=PERM_INVENTORY_SCAN) & Q(inventory__organization__admins__in=[self.user]))
)
allowed_deploy = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY]
allowed_check = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK]
team_ids = Team.objects.filter(users__in=[self.user])
# TODO: I think the below queries can be combined
deploy_permissions_ids = Permission.objects.filter(
Q(user=self.user) | Q(team__in=team_ids),
permission_type__in=allowed_deploy,
)
check_permissions_ids = Permission.objects.filter(
Q(user=self.user) | Q(team__in=team_ids),
permission_type__in=allowed_check,
)
perm_deploy_ids = base_qs.filter(
job_type=PERM_INVENTORY_DEPLOY,
inventory__permissions__in=deploy_permissions_ids,
project__permissions__in=deploy_permissions_ids,
inventory__permissions__pk=F('project__permissions__pk'),
)
perm_check_ids = base_qs.filter(
job_type=PERM_INVENTORY_CHECK,
inventory__permissions__in=check_permissions_ids,
project__permissions__in=check_permissions_ids,
inventory__permissions__pk=F('project__permissions__pk'),
)
return base_qs.filter(
Q(id__in=org_admin_ids) |
Q(id__in=perm_deploy_ids) |
Q(id__in=perm_check_ids)
job_template__in=JobTemplate.accessible_objects(self.user, {'read': True})
)
def can_add(self, data):
@ -938,21 +893,11 @@ class AdHocCommandAccess(BaseAccess):
return qs
credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True))
team_ids = set(Team.objects.filter( users__in=[self.user]).values_list('id', flat=True))
permission_ids = set(Permission.objects.filter(
Q(user=self.user) | Q(team__in=team_ids),
permission_type__in=PERMISSION_TYPES_ALLOWING_INVENTORY_READ,
run_ad_hoc_commands=True,
).values_list('id', flat=True))
inventory_qs = self.user.get_queryset(Inventory)
inventory_qs = inventory_qs.filter(Q(permissions__in=permission_ids) | Q(organization__admins__in=[self.user]))
inventory_ids = set(inventory_qs.values_list('id', flat=True))
inventory_qs = Inventory.accessible_objects(self.user, {'read': True, 'execute': True})
qs = qs.filter(
credential_id__in=credential_ids,
inventory_id__in=inventory_ids,
inventory__in=inventory_qs,
)
return qs
@ -1183,7 +1128,8 @@ class ScheduleAccess(BaseAccess):
if self.user.is_superuser:
return True
if obj and obj.unified_job_template:
return obj.unified_job_template.accessible_by(self.user, {'read':True})
job_class = obj.unified_job_template
return self.user.can_access(type(job_class), 'read', obj.unified_job_template)
else:
return False
@ -1193,7 +1139,7 @@ class ScheduleAccess(BaseAccess):
pk = get_pk_from_dict(data, 'unified_job_template')
obj = get_object_or_400(UnifiedJobTemplate, pk=pk)
if obj:
return obj.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
return self.user.can_access(type(obj), 'change', obj, None)
else:
return False
@ -1201,7 +1147,8 @@ class ScheduleAccess(BaseAccess):
if self.user.is_superuser:
return True
if obj and obj.unified_job_template:
return obj.unified_job_template.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
job_class = obj.unified_job_template
return self.user.can_access(type(job_class), 'change', job_class, None)
else:
return False
@ -1209,7 +1156,8 @@ class ScheduleAccess(BaseAccess):
if self.user.is_superuser:
return True
if obj and obj.unified_job_template:
return obj.unified_job_template.accessible_by(self.user, {'read':True, 'update':True, 'write':True})
job_class = obj.unified_job_template
return self.user.can_access(type(job_class), 'change', job_class, None)
else:
return False
@ -1287,10 +1235,6 @@ class ActivityStreamAccess(BaseAccess):
#Project Update Filter
qs.filter(project_update__project__in=project_qs)
#Permission Filter
permission_qs = self.user.get_queryset(Permission)
qs.filter(permission__in=permission_qs)
#Job Template Filter
jobtemplate_qs = self.user.get_queryset(JobTemplate)
qs.filter(job_template__in=jobtemplate_qs)

View File

@ -243,18 +243,26 @@ class ImplicitRoleField(models.ForeignKey):
def _calc_original_parents(self, instance):
if not hasattr(self, '__original_parent_roles'):
setattr(self, '__original_parent_roles', []) # do not just self.__original_parent_roles=[], it's not the same here
paths = self.parent_role if type(self.parent_role) is list else [self.parent_role]
original_parent_roles = set()
for path in paths:
if path.startswith("singleton:"):
parents = [Role.singleton(path[10:])]
else:
parents = resolve_role_field(instance, path)
for parent in parents:
original_parent_roles.add(parent)
setattr(self, '__original_parent_roles', set()) # do not just self.__original_parent_roles=[], it's not the same here, apparently.
# NOTE: The above setattr is required to be called bofore
# _resolve_parent_roles because we can end up recursing, so the enclosing
# if not hasattr protects against this.
original_parent_roles = self._resolve_parent_roles(instance)
setattr(self, '__original_parent_roles', original_parent_roles)
def _resolve_parent_roles(self, instance):
paths = self.parent_role if type(self.parent_role) is list else [self.parent_role]
parent_roles = set()
for path in paths:
if path.startswith("singleton:"):
parents = [Role.singleton(path[10:])]
else:
parents = resolve_role_field(instance, path)
for parent in parents:
parent_roles.add(parent)
return parent_roles
def _post_save(self, instance, created, *args, **kwargs):
# Ensure that our field gets initialized after our first save
this_role = getattr(instance, self.name)
@ -269,16 +277,8 @@ class ImplicitRoleField(models.ForeignKey):
self._calc_original_parents(instance)
return
paths = self.parent_role if type(self.parent_role) is list else [self.parent_role]
original_parents = getattr(self, '__original_parent_roles')
new_parents = set()
for path in paths:
if path.startswith("singleton:"):
parents = [Role.singleton(path[10:])]
else:
parents = resolve_role_field(instance, path)
for parent in parents:
new_parents.add(parent)
new_parents = self._resolve_parent_roles(instance)
with batch_role_ancestor_rebuilding():
for role in original_parents - new_parents:

View File

@ -3,6 +3,7 @@
# Django
from django.conf import settings # noqa
from django.contrib.contenttypes.fields import GenericRelation
# AWX
from awx.main.models.base import * # noqa
@ -38,11 +39,13 @@ _PythonSerializer.handle_m2m_field = _new_handle_m2m_field
from django.contrib.auth.models import User # noqa
from awx.main.access import * # noqa
User.add_to_class('get_queryset', get_user_queryset)
User.add_to_class('can_access', check_user_access)
User.add_to_class('accessible_by', user_accessible_by)
User.add_to_class('accessible_objects', user_accessible_objects)
User.add_to_class('admin_role', user_admin_role)
User.add_to_class('role_permissions', GenericRelation('main.RolePermission'))
# Import signal handlers only after models have been defined.
import awx.main.signals # noqa

View File

@ -111,10 +111,12 @@ class Inventory(CommonModel, ResourceMixin):
updater_role = ImplicitRoleField(
role_name='Inventory Updater',
role_description='May update the inventory',
permissions = {'read': True, 'update': True}
)
executor_role = ImplicitRoleField(
role_name='Inventory Executor',
role_description='May execute jobs against this inventory',
permissions = {'read': True, 'execute': True}
)
def get_absolute_url(self):
@ -545,6 +547,7 @@ class Group(CommonModelNameNotUnique, ResourceMixin):
@transaction.atomic
def delete_recursive(self):
from awx.main.utils import ignore_inventory_computed_fields
from awx.main.tasks import update_inventory_computed_fields
from awx.main.signals import disable_activity_stream
@ -1051,7 +1054,7 @@ class InventorySourceOptions(BaseModel):
return ','.join(choices)
class InventorySource(UnifiedJobTemplate, InventorySourceOptions, ResourceMixin):
class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
class Meta:
app_label = 'main'

View File

@ -32,7 +32,10 @@ class ResourceMixin(models.Model):
performant to resolve the resource in question then call
`myresource.get_permissions(user)`.
'''
return ResourceMixin._accessible_objects(cls, user, permissions)
@staticmethod
def _accessible_objects(cls, user, permissions):
qs = cls.objects.filter(
role_permissions__role__ancestors__members=user
)

View File

@ -459,30 +459,19 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
self.check_get_list(url, 'nobody', qs)
self.check_get_list(url, None, qs, expect=401)
# Explicitly give other user admin permission on the inventory (still
# Explicitly give other user updater permission on the inventory (still
# not allowed to run ad hoc commands).
user_perm_url = reverse('api:user_permissions_list', args=(self.other_django_user.pk,))
user_perm_data = {
'name': 'Allow Other to Admin Inventory',
'inventory': self.inventory.pk,
'permission_type': 'admin',
}
user_roles_list_url = reverse('api:user_roles_list', args=(self.other_django_user.pk,))
with self.current_user('admin'):
response = self.post(user_perm_url, user_perm_data, expect=201)
user_perm_id = response['id']
response = self.post(user_roles_list_url, {"id": self.inventory.updater_role.id}, expect=204)
with self.current_user('other'):
self.run_test_ad_hoc_command(expect=403)
self.check_get_list(url, 'other', qs)
# Update permission to allow other user to run ad hoc commands. Fails
# Add executor role permissions to other. Fails
# when other user can't read credential.
user_perm_url = reverse('api:permission_detail', args=(user_perm_id,))
user_perm_data.update({
'name': 'Allow Other to Admin Inventory and Run Ad Hoc Commands',
'run_ad_hoc_commands': True,
})
with self.current_user('admin'):
response = self.patch(user_perm_url, user_perm_data, expect=200)
response = self.post(user_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
with self.current_user('other'):
self.run_test_ad_hoc_command(expect=403)
@ -496,15 +485,9 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
self.check_get_list(url, 'other', qs)
# Explicitly give nobody user read permission on the inventory.
user_perm_url = reverse('api:user_permissions_list', args=(self.nobody_django_user.pk,))
user_perm_data = {
'name': 'Allow Nobody to Read Inventory',
'inventory': self.inventory.pk,
'permission_type': 'read',
}
nobody_roles_list_url = reverse('api:user_roles_list', args=(self.nobody_django_user.pk,))
with self.current_user('admin'):
response = self.post(user_perm_url, user_perm_data, expect=201)
user_perm_id = response['id']
response = self.post(nobody_roles_list_url, {"id": self.inventory.auditor_role.id}, expect=204)
with self.current_user('nobody'):
self.run_test_ad_hoc_command(credential=other_cred.pk, expect=403)
self.check_get_list(url, 'other', qs)
@ -520,13 +503,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
# Give the nobody user the run_ad_hoc_commands flag, and can now see
# the one ad hoc command previously run.
user_perm_url = reverse('api:permission_detail', args=(user_perm_id,))
user_perm_data.update({
'name': 'Allow Nobody to Read Inventory and Run Ad Hoc Commands',
'run_ad_hoc_commands': True,
})
with self.current_user('admin'):
response = self.patch(user_perm_url, user_perm_data, expect=200)
response = self.post(nobody_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
qs = AdHocCommand.objects.filter(credential_id=nobody_cred.pk)
self.assertEqual(qs.count(), 1)
self.check_get_list(url, 'nobody', qs)
@ -947,7 +925,7 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
self.delete(url, expect=405)
with self.current_user('normal'):
response = self.get(url, expect=200)
#self.assertEqual(response['count'], 1) # FIXME: Enable once activity stream RBAC is fixed.
self.assertEqual(response['count'], 1)
self.post(url, {}, expect=405)
self.put(url, {}, expect=405)
self.patch(url, {}, expect=405)
@ -1026,29 +1004,17 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
# Create another unrelated inventory permission with run_ad_hoc_commands
# set; this tests an edge case in the RBAC query where we'll return
# can_run_ad_hoc_commands = True when we shouldn't.
nobody_perm_url = reverse('api:user_permissions_list', args=(self.nobody_django_user.pk,))
nobody_perm_data = {
'name': 'Allow Nobody to Read Inventory',
'inventory': self.inventory.pk,
'permission_type': 'read',
'run_ad_hoc_commands': True,
}
nobody_roles_list_url = reverse('api:user_roles_list', args=(self.nobody_django_user.pk,))
with self.current_user('admin'):
response = self.post(nobody_perm_url, nobody_perm_data, expect=201)
response = self.post(nobody_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
# Create a credential for the other user and explicitly give other
# user admin permission on the inventory (still not allowed to run ad
# hoc commands; can get the list but can't see any items).
other_cred = self.create_test_credential(user=self.other_django_user)
user_perm_url = reverse('api:user_permissions_list', args=(self.other_django_user.pk,))
user_perm_data = {
'name': 'Allow Other to Admin Inventory',
'inventory': self.inventory.pk,
'permission_type': 'admin',
}
user_roles_list_url = reverse('api:user_roles_list', args=(self.other_django_user.pk,))
with self.current_user('admin'):
response = self.post(user_perm_url, user_perm_data, expect=201)
user_perm_id = response['id']
response = self.post(user_roles_list_url, {"id": self.inventory.updater_role.id}, expect=204)
with self.current_user('other'):
response = self.get(url, expect=200)
self.assertEqual(response['count'], 0)
@ -1058,13 +1024,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
# Update permission to allow other user to run ad hoc commands. Can
# only see his own ad hoc commands (because of credential permission).
user_perm_url = reverse('api:permission_detail', args=(user_perm_id,))
user_perm_data.update({
'name': 'Allow Other to Admin Inventory and Run Ad Hoc Commands',
'run_ad_hoc_commands': True,
})
with self.current_user('admin'):
response = self.patch(user_perm_url, user_perm_data, expect=200)
response = self.post(user_roles_list_url, {"id": self.inventory.executor_role.id}, expect=204)
with self.current_user('other'):
response = self.get(url, expect=200)
self.assertEqual(response['count'], 0)

View File

@ -2,7 +2,6 @@
# All Rights Reserved.
# Python
import datetime
import glob
import json
import os
@ -14,7 +13,6 @@ import time
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.utils.timezone import now
# AWX
from awx.main.models import * # noqa
@ -47,9 +45,9 @@ class InventoryTest(BaseTest):
self.setup_instances()
self.setup_users()
self.organizations = self.make_organizations(self.super_django_user, 3)
self.organizations[0].deprecated_admins.add(self.normal_django_user)
self.organizations[0].deprecated_users.add(self.other_django_user)
self.organizations[0].deprecated_users.add(self.normal_django_user)
self.organizations[0].admin_role.members.add(self.normal_django_user)
self.organizations[0].member_role.members.add(self.other_django_user)
self.organizations[0].member_role.members.add(self.normal_django_user)
self.inventory_a = Inventory.objects.create(name='inventory-a', description='foo', organization=self.organizations[0])
self.inventory_b = Inventory.objects.create(name='inventory-b', description='bar', organization=self.organizations[1])
@ -58,10 +56,7 @@ class InventoryTest(BaseTest):
# create a permission here on the 'other' user so they have edit access on the org
# we may add another permission type later.
self.perm_read = Permission.objects.create(
inventory = self.inventory_b,
user = self.other_django_user,
permission_type = 'read')
self.inventory_b.auditor_role.members.add(self.other_django_user)
def tearDown(self):
super(InventoryTest, self).tearDown()
@ -78,11 +73,11 @@ class InventoryTest(BaseTest):
self.check_get_list(url, self.super_django_user, qs)
# an org admin can list inventories but is filtered to what he adminsters
normal_qs = qs.filter(organization__deprecated_admins__in=[self.normal_django_user])
normal_qs = qs.filter(organization__admin_role__members=self.normal_django_user)
self.check_get_list(url, self.normal_django_user, normal_qs)
# a user who is on a team who has a read permissions on an inventory can see filtered inventories
other_qs = qs.filter(permissions__user__in=[self.other_django_user])
other_qs = Inventory.accessible_objects(self.other_django_user, {'read': True}).distinct()
self.check_get_list(url, self.other_django_user, other_qs)
# a regular user not part of anything cannot see any inventories
@ -263,24 +258,20 @@ class InventoryTest(BaseTest):
def test_inventory_access_deleted_permissions(self):
temp_org = self.make_organizations(self.super_django_user, 1)[0]
temp_org.deprecated_admins.add(self.normal_django_user)
temp_org.deprecated_users.add(self.other_django_user)
temp_org.deprecated_users.add(self.normal_django_user)
temp_org.admin_role.members.add(self.normal_django_user)
temp_org.member_role.members.add(self.other_django_user)
temp_org.member_role.members.add(self.normal_django_user)
temp_inv = temp_org.inventories.create(name='Delete Org Inventory')
temp_inv.groups.create(name='Delete Org Inventory Group')
temp_perm_read = Permission.objects.create(
inventory = temp_inv,
user = self.other_django_user,
permission_type = 'read'
)
temp_inv.auditor_role.members.add(self.other_django_user)
reverse('api:organization_detail', args=(temp_org.pk,))
inventory_detail = reverse('api:inventory_detail', args=(temp_inv.pk,))
permission_detail = reverse('api:permission_detail', args=(temp_perm_read.pk,))
auditor_role_users_list = reverse('api:role_users_list', args=(temp_inv.auditor_role.pk,))
self.get(inventory_detail, expect=200, auth=self.get_other_credentials())
self.delete(permission_detail, expect=204, auth=self.get_super_credentials())
self.post(auditor_role_users_list, data={'disassociate': True, "id": self.other_django_user.id}, expect=204, auth=self.get_super_credentials())
self.get(inventory_detail, expect=403, auth=self.get_other_credentials())
def test_create_inventory_script(self):
@ -335,10 +326,8 @@ class InventoryTest(BaseTest):
self.post(hosts, data=new_host_b, expect=403, auth=self.get_nobody_credentials())
# a normal user with inventory edit permissions (on any inventory) can create hosts
Permission.objects.create(
user = self.other_django_user,
inventory = Inventory.objects.get(pk=inv.pk),
permission_type = PERM_INVENTORY_WRITE)
inv.admin_role.members.add(self.other_django_user)
host_data3 = self.post(hosts, data=new_host_c, expect=201, auth=self.get_other_credentials())
# Port should be split out into host variables, other variables kept intact.
@ -393,11 +382,6 @@ class InventoryTest(BaseTest):
# a normal user with inventory edit permissions (on any inventory) can create groups
# already done!
#edit_perm = Permission.objects.create(
# user = self.other_django_user,
# inventory = Inventory.objects.get(pk=inv.pk),
# permission_type = PERM_INVENTORY_WRITE
#)
self.post(groups, data=new_group_c, expect=201, auth=self.get_other_credentials())
# hostnames must be unique inside an organization
@ -417,9 +401,10 @@ class InventoryTest(BaseTest):
del_children_url = reverse('api:group_children_list', args=(del_group.pk,))
nondel_url = reverse('api:group_detail',
args=(Group.objects.get(name='nondel').pk,))
assert(inv.accessible_by(self.normal_django_user, {'read': True}))
del_group.delete()
nondel_detail = self.get(nondel_url, expect=200, auth=self.get_normal_credentials())
self.post(del_children_url, data=nondel_detail, expect=403, auth=self.get_normal_credentials())
self.post(del_children_url, data=nondel_detail, expect=400, auth=self.get_normal_credentials())
#################################################
@ -656,11 +641,7 @@ class InventoryTest(BaseTest):
gx5 = Group.objects.create(name='group-X5', inventory=inva)
gx5.parents.add(gx4)
Permission.objects.create(
inventory = inva,
user = self.other_django_user,
permission_type = PERM_INVENTORY_WRITE
)
inva.admin_role.members.add(self.other_django_user)
# data used for testing listing all hosts that are transitive members of a group
g2 = Group.objects.get(name='web4')
@ -1115,59 +1096,6 @@ class InventoryTest(BaseTest):
self.assertEqual(response['hosts']['total'], 8)
self.assertEqual(response['hosts']['failed'], 8)
def test_dashboard_inventory_graph_view(self):
url = reverse('api:dashboard_inventory_graph_view')
# Test with zero hosts.
with self.current_user(self.super_django_user):
response = self.get(url)
self.assertFalse(sum([x[1] for x in response['hosts']]))
# Create hosts in inventory_a, with created one day apart, and check
# the time series results.
dtnow = now()
hostnames = list('abcdefg')
for x in xrange(len(hostnames) - 1, -1, -1):
hostname = hostnames[x]
created = dtnow - datetime.timedelta(days=x, seconds=60)
self.inventory_a.hosts.create(name=hostname, created=created)
with self.current_user(self.super_django_user):
response = self.get(url)
for n, d in enumerate(reversed(response['hosts'])):
self.assertEqual(d[1], max(len(hostnames) - n, 0))
# Create more hosts a day apart in inventory_b and check the time
# series results.
hostnames2 = list('hijklmnop')
for x in xrange(len(hostnames2) - 1, -1, -1):
hostname = hostnames2[x]
created = dtnow - datetime.timedelta(days=x, seconds=120)
self.inventory_b.hosts.create(name=hostname, created=created)
with self.current_user(self.super_django_user):
response = self.get(url)
for n, d in enumerate(reversed(response['hosts'])):
self.assertEqual(d[1], max(len(hostnames2) - n, 0) + max(len(hostnames) - n, 0))
# Now create some hosts in inventory_a with the same hostnames already
# used in inventory_b; duplicate hostnames should only be counted the
# first time they were seen in inventory_b.
hostnames3 = list('lmnop')
for x in xrange(len(hostnames3) - 1, -1, -1):
hostname = hostnames3[x]
created = dtnow - datetime.timedelta(days=x, seconds=180)
self.inventory_a.hosts.create(name=hostname, created=created)
with self.current_user(self.super_django_user):
response = self.get(url)
for n, d in enumerate(reversed(response['hosts'])):
self.assertEqual(d[1], max(len(hostnames2) - n, 0) + max(len(hostnames) - n, 0))
# Delete recently added hosts and verify the count drops.
hostnames4 = list('defg')
for host in Host.objects.filter(name__in=hostnames4):
host.delete()
with self.current_user(self.super_django_user):
response = self.get(url)
for n, d in enumerate(reversed(response['hosts'])):
count = max(len(hostnames2) - n, 0) + max(len(hostnames) - n, 0)
if n == 0:
count -= 4
self.assertEqual(d[1], count)
@override_settings(CELERY_ALWAYS_EAGER=True,
CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
@ -1181,9 +1109,9 @@ class InventoryUpdatesTest(BaseTransactionTest):
self.setup_instances()
self.setup_users()
self.organization = self.make_organizations(self.super_django_user, 1)[0]
self.organization.deprecated_admins.add(self.normal_django_user)
self.organization.deprecated_users.add(self.other_django_user)
self.organization.deprecated_users.add(self.normal_django_user)
self.organization.admin_role.members.add(self.normal_django_user)
self.organization.member_role.members.add(self.other_django_user)
self.organization.member_role.members.add(self.normal_django_user)
self.inventory = self.organization.inventories.create(name='Cloud Inventory')
self.group = self.inventory.groups.create(name='Cloud Group')
self.inventory2 = self.organization.inventories.create(name='Cloud Inventory 2')
@ -1256,7 +1184,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
url = reverse('api:inventory_source_hosts_list', args=(inventory_source.pk,))
response = self.get(url, expect=200)
self.assertNotEqual(response['count'], 0)
for host in inventory.hosts:
for host in inventory.hosts.all():
source_pks = host.inventory_sources.values_list('pk', flat=True)
self.assertTrue(inventory_source.pk in source_pks)
self.assertTrue(host.has_inventory_sources)
@ -1270,7 +1198,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
url = reverse('api:host_inventory_sources_list', args=(host.pk,))
response = self.get(url, expect=200)
self.assertNotEqual(response['count'], 0)
for group in inventory.groups:
for group in inventory.groups.all():
source_pks = group.inventory_sources.values_list('pk', flat=True)
self.assertTrue(inventory_source.pk in source_pks)
self.assertTrue(group.has_inventory_sources)
@ -1293,7 +1221,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
self.assertNotEqual(response['count'], 0)
# Try to set a source on a child group that was imported. Should not
# be allowed.
for group in inventory_source.group.children:
for group in inventory_source.group.children.all():
inv_src_2 = group.inventory_source
inv_src_url2 = reverse('api:inventory_source_detail', args=(inv_src_2.pk,))
with self.current_user(self.super_django_user):
@ -1540,16 +1468,9 @@ class InventoryUpdatesTest(BaseTransactionTest):
self.post(inv_src_update_url, {}, expect=403)
# If given read permission to the inventory, other user should be able
# to see the inventory source and update view, but not start an update.
other_perms_url = reverse('api:user_permissions_list',
args=(self.other_django_user.pk,))
other_perms_data = {
'name': 'read only inventory permission for other',
'user': self.other_django_user.pk,
'inventory': self.inventory.pk,
'permission_type': 'read',
}
user_roles_list_url = reverse('api:user_roles_list', args=(self.other_django_user.pk,))
with self.current_user(self.super_django_user):
self.post(other_perms_url, other_perms_data, expect=201)
self.post(user_roles_list_url, {"id": self.inventory.auditor_role.id}, expect=204)
with self.current_user(self.other_django_user):
self.get(inv_src_url, expect=200)
response = self.get(inv_src_update_url, expect=200)
@ -1557,14 +1478,8 @@ class InventoryUpdatesTest(BaseTransactionTest):
self.post(inv_src_update_url, {}, expect=403)
# Once given write permission, the normal user is able to update the
# inventory source.
other_perms_data = {
'name': 'read-write inventory permission for other',
'user': self.other_django_user.pk,
'inventory': self.inventory.pk,
'permission_type': 'write',
}
with self.current_user(self.super_django_user):
self.post(other_perms_url, other_perms_data, expect=201)
self.post(user_roles_list_url, {"id": self.inventory.admin_role.id}, expect=204)
with self.current_user(self.other_django_user):
self.get(inv_src_url, expect=200)
response = self.get(inv_src_update_url, expect=200)
@ -1649,7 +1564,7 @@ class InventoryUpdatesTest(BaseTransactionTest):
inventory_source.overwrite = True
inventory_source.save()
self.check_inventory_source(inventory_source, initial=False)
for host in self.inventory.hosts:
for host in self.inventory.hosts.all():
self.assertEqual(host.variables_dict['ec2_instance_type'], instance_type)
# Try invalid instance filters that should be ignored:

View File

@ -19,7 +19,7 @@ class LicenseTests(BaseTest):
self.setup_users()
u = self.super_django_user
org = Organization.objects.create(name='o1', created_by=u)
org.deprecated_admins.add(self.normal_django_user)
org.admin_role.members.add(self.normal_django_user)
self.inventory = Inventory.objects.create(name='hi', organization=org, created_by=u)
Host.objects.create(name='a1', inventory=self.inventory, created_by=u)
Host.objects.create(name='a2', inventory=self.inventory, created_by=u)

View File

@ -88,12 +88,12 @@ class OrganizationsTest(BaseTest):
# nobody_user is a user not a member of any organizations
for x in self.organizations:
x.deprecated_admins.add(self.super_django_user)
x.deprecated_users.add(self.super_django_user)
x.deprecated_users.add(self.other_django_user)
x.admin_role.members.add(self.super_django_user)
x.member_role.members.add(self.super_django_user)
x.member_role.members.add(self.other_django_user)
self.organizations[0].deprecated_users.add(self.normal_django_user)
self.organizations[1].deprecated_admins.add(self.normal_django_user)
self.organizations[0].member_role.members.add(self.normal_django_user)
self.organizations[1].admin_role.members.add(self.normal_django_user)
def test_get_organization_list(self):
url = reverse('api:organization_list')

View File

@ -75,10 +75,10 @@ class ProjectsTest(BaseTransactionTest):
for x in self.organizations:
# NOTE: superuser does not have to be explicitly added to admin group
# x.admins.add(self.super_django_user)
x.deprecated_users.add(self.super_django_user)
x.member_role.members.add(self.super_django_user)
self.organizations[0].deprecated_users.add(self.normal_django_user)
self.organizations[1].deprecated_admins.add(self.normal_django_user)
self.organizations[0].member_role.members.add(self.normal_django_user)
self.organizations[1].admin_role.members.add(self.normal_django_user)
self.team1 = Team.objects.create(
name = 'team1', organization = self.organizations[0]
@ -97,8 +97,8 @@ class ProjectsTest(BaseTransactionTest):
self.team2.projects.add(self.projects[5])
self.team1.save()
self.team2.save()
self.team1.deprecated_users.add(self.normal_django_user)
self.team2.deprecated_users.add(self.other_django_user)
self.team1.member_role.members.add(self.normal_django_user)
self.team2.member_role.members.add(self.other_django_user)
def test_playbooks(self):
def write_test_file(project, name, content):
@ -312,7 +312,7 @@ class ProjectsTest(BaseTransactionTest):
# Verify that creatorship doesn't imply access if access is removed
a_new_proj = self.make_project(created_by=self.other_django_user, playbook_content=TEST_PLAYBOOK)
self.organizations[0].deprecated_admins.add(self.other_django_user)
self.organizations[0].admin_role.members.add(self.other_django_user)
self.organizations[0].projects.add(a_new_proj)
proj_detail = reverse('api:project_detail', args=(a_new_proj.pk,))
self.patch(proj_detail, data=dict(description="test"), expect=200, auth=self.get_other_credentials())
@ -337,7 +337,7 @@ class ProjectsTest(BaseTransactionTest):
self.assertEquals(got['url'], reverse('api:team_detail', args=(self.team1.pk,)))
got = self.get(team1, expect=200, auth=self.get_normal_credentials())
got = self.get(team1, expect=403, auth=self.get_other_credentials())
self.team1.deprecated_users.add(User.objects.get(username='other'))
self.team1.member_role.members.add(User.objects.get(username='other'))
self.team1.save()
got = self.get(team1, expect=200, auth=self.get_other_credentials())
got = self.get(team1, expect=403, auth=self.get_nobody_credentials())
@ -422,7 +422,7 @@ class ProjectsTest(BaseTransactionTest):
team = Team.objects.filter( organization__pk=self.organizations[1].pk)[0]
team_users = reverse('api:team_users_list', args=(team.pk,))
for x in team.deprecated_users.all():
team.deprecated_users.remove(x)
team.member_role.members.remove(x)
team.save()
# can list uses on teams
@ -787,7 +787,7 @@ class ProjectsTest(BaseTransactionTest):
# User is still a team member
self.get(reverse('api:project_detail', args=(project.pk,)), expect=200, auth=self.get_other_credentials())
team.deprecated_users.remove(self.other_django_user)
team.member_role.members.remove(self.other_django_user)
# User is no longer a team member and has no permissions
self.get(reverse('api:project_detail', args=(project.pk,)), expect=403, auth=self.get_other_credentials())
@ -1351,7 +1351,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
'scm_url': scm_url,
}
org = self.make_organizations(self.super_django_user, 1)[0]
org.deprecated_admins.add(self.normal_django_user)
org.admin_role.members.add(self.normal_django_user)
with self.current_user(self.super_django_user):
del_proj = self.post(projects_url, project_data, expect=201)
del_proj = Project.objects.get(pk=del_proj["id"])

View File

@ -54,12 +54,12 @@ class ScheduleTest(BaseTest):
self.setup_instances()
self.setup_users()
self.organizations = self.make_organizations(self.super_django_user, 2)
self.organizations[0].deprecated_admins.add(self.normal_django_user)
self.organizations[0].deprecated_users.add(self.other_django_user)
self.organizations[0].deprecated_users.add(self.normal_django_user)
self.organizations[0].admin_role.members.add(self.normal_django_user)
self.organizations[0].member_role.members.add(self.other_django_user)
self.organizations[0].member_role.members.add(self.normal_django_user)
self.diff_org_user = self.make_user('fred')
self.organizations[1].deprecated_users.add(self.diff_org_user)
self.organizations[1].member_role.members.add(self.diff_org_user)
self.cloud_source = Credential.objects.create(kind='awx', user=self.super_django_user,
username='Dummy', password='Dummy')
@ -71,11 +71,7 @@ class ScheduleTest(BaseTest):
self.first_inventory_source.source = 'ec2'
self.first_inventory_source.save()
Permission.objects.create(
inventory = self.first_inventory,
user = self.other_django_user,
permission_type = 'read'
)
self.first_inventory.auditor_role.members.add(self.other_django_user)
self.second_inventory = Inventory.objects.create(name='test_inventory_2', description='for org 0', organization=self.organizations[0])
self.second_inventory.hosts.create(name='host_2')
@ -139,11 +135,7 @@ class ScheduleTest(BaseTest):
self.post(first_url, data=unauth_schedule, expect=403)
#give normal user write access and then they can post
Permission.objects.create(
user = self.other_django_user,
inventory = self.first_inventory,
permission_type = PERM_INVENTORY_WRITE
)
self.first_inventory.admin_role.members.add(self.other_django_user)
auth_schedule = unauth_schedule
with self.current_user(self.other_django_user):
self.post(first_url, data=auth_schedule, expect=201)

View File

@ -100,7 +100,7 @@ class AuthTokenProxyTest(BaseTest):
self.setup_users()
self.setup_instances()
self.organizations = self.make_organizations(self.super_django_user, 2)
self.organizations[0].deprecated_admins.add(self.normal_django_user)
self.organizations[0].admin_role.members.add(self.normal_django_user)
self.assertIn('REMOTE_ADDR', settings.REMOTE_HOST_HEADERS)
self.assertIn('REMOTE_HOST', settings.REMOTE_HOST_HEADERS)
@ -174,10 +174,10 @@ class UsersTest(BaseTest):
super(UsersTest, self).setUp()
self.setup_users()
self.organizations = self.make_organizations(self.super_django_user, 2)
self.organizations[0].deprecated_admins.add(self.normal_django_user)
self.organizations[0].deprecated_users.add(self.other_django_user)
self.organizations[0].deprecated_users.add(self.normal_django_user)
self.organizations[1].deprecated_users.add(self.other_django_user)
self.organizations[0].admin_role.members.add(self.normal_django_user)
self.organizations[0].member_role.members.add(self.other_django_user)
self.organizations[0].member_role.members.add(self.normal_django_user)
self.organizations[1].member_role.members.add(self.other_django_user)
def test_user_creation_fails_without_password(self):
url = reverse('api:user_list')