mirror of
https://github.com/ansible/awx.git
synced 2024-10-31 15:21:13 +03:00
Merge pull request #1650 from anoek/performance
More RBAC optimizations
This commit is contained in:
commit
2d4e9f15df
@ -340,16 +340,18 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
return None
|
||||
elif isinstance(obj, User):
|
||||
return obj.date_joined
|
||||
else:
|
||||
elif hasattr(obj, 'created'):
|
||||
return obj.created
|
||||
return None
|
||||
|
||||
def get_modified(self, obj):
|
||||
if obj is None:
|
||||
return None
|
||||
elif isinstance(obj, User):
|
||||
return obj.last_login # Not actually exposed for User.
|
||||
else:
|
||||
elif hasattr(obj, 'modified'):
|
||||
return obj.modified
|
||||
return None
|
||||
|
||||
def build_standard_field(self, field_name, model_field):
|
||||
# DRF 3.3 serializers.py::build_standard_field() -> utils/field_mapping.py::get_field_kwargs() short circuits
|
||||
|
@ -18,7 +18,6 @@ from django.db.models.fields.related import (
|
||||
ReverseManyRelatedObjectsDescriptor,
|
||||
)
|
||||
from django.utils.encoding import smart_text
|
||||
from django.utils.timezone import now
|
||||
|
||||
# AWX
|
||||
from awx.main.models.rbac import batch_role_ancestor_rebuilding
|
||||
@ -92,9 +91,7 @@ class ImplicitRoleDescriptor(ReverseSingleRelatedObjectDescriptor):
|
||||
class ImplicitRoleField(models.ForeignKey):
|
||||
"""Implicitly creates a role entry for a resource"""
|
||||
|
||||
def __init__(self, role_name=None, role_description=None, parent_role=None, *args, **kwargs):
|
||||
self.role_name = role_name
|
||||
self.role_description = role_description if role_description else ""
|
||||
def __init__(self, parent_role=None, *args, **kwargs):
|
||||
self.parent_role = parent_role
|
||||
|
||||
kwargs.setdefault('to', 'Role')
|
||||
@ -104,8 +101,6 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super(ImplicitRoleField, self).deconstruct()
|
||||
kwargs['role_name'] = self.role_name
|
||||
kwargs['role_description'] = self.role_description
|
||||
kwargs['parent_role'] = self.parent_role
|
||||
return name, path, args, kwargs
|
||||
|
||||
@ -190,11 +185,7 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
if cur_role is None:
|
||||
missing_roles.append(
|
||||
Role_(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
role_field=implicit_role_field.name,
|
||||
name=implicit_role_field.role_name,
|
||||
description=implicit_role_field.role_description,
|
||||
content_type_id=ct_id,
|
||||
object_id=instance.id
|
||||
)
|
||||
@ -208,7 +199,7 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
updates[role.role_field] = role.id
|
||||
role_ids.append(role.id)
|
||||
type(instance).objects.filter(pk=instance.pk).update(**updates)
|
||||
Role_._simultaneous_ancestry_rebuild(role_ids)
|
||||
Role_.rebuild_role_ancestor_list(role_ids, [])
|
||||
|
||||
# Update parentage if necessary
|
||||
for implicit_role_field in getattr(instance.__class__, '__implicit_role_fields'):
|
||||
@ -247,12 +238,7 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
if qs.count() >= 1:
|
||||
role = qs[0]
|
||||
else:
|
||||
role = Role_.objects.create(created=now(),
|
||||
modified=now(),
|
||||
role_field=path,
|
||||
singleton_name=singleton_name,
|
||||
name=singleton_name,
|
||||
description=singleton_name)
|
||||
role = Role_.objects.create(singleton_name=singleton_name, role_field=singleton_name)
|
||||
parents = [role.id]
|
||||
else:
|
||||
parents = resolve_role_field(instance, path)
|
||||
@ -269,4 +255,4 @@ class ImplicitRoleField(models.ForeignKey):
|
||||
Role_ = get_current_apps().get_model('main', 'Role')
|
||||
child_ids = [x for x in Role_.parents.through.objects.filter(to_role_id__in=role_ids).distinct().values_list('from_role_id', flat=True)]
|
||||
Role_.objects.filter(id__in=role_ids).delete()
|
||||
Role_._simultaneous_ancestry_rebuild(child_ids)
|
||||
Role_.rebuild_role_ancestor_list([], child_ids)
|
||||
|
@ -2,21 +2,21 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
import taggit.managers
|
||||
import awx.main.fields
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('taggit', '0002_auto_20150616_2121'),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('main', '0007_v300_active_flag_removal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
#
|
||||
# Patch up existing
|
||||
#
|
||||
migrations.RenameField(
|
||||
'Organization',
|
||||
'admins',
|
||||
@ -47,300 +47,6 @@ class Migration(migrations.Migration):
|
||||
name='deprecated_projects',
|
||||
field=models.ManyToManyField(related_name='deprecated_teams', to='main.Project', blank=True),
|
||||
),
|
||||
|
||||
migrations.CreateModel(
|
||||
name='RoleAncestorEntry',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('role_field', models.TextField()),
|
||||
('content_type_id', models.PositiveIntegerField(null=False)),
|
||||
('object_id', models.PositiveIntegerField(null=False)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_role_ancestors',
|
||||
'verbose_name_plural': 'role_ancestors',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('created', models.DateTimeField(default=None, editable=False)),
|
||||
('modified', models.DateTimeField(default=None, editable=False)),
|
||||
('description', models.TextField(default=b'', blank=True)),
|
||||
('name', models.CharField(max_length=512)),
|
||||
('singleton_name', models.TextField(default=None, unique=True, null=True, db_index=True)),
|
||||
('object_id', models.PositiveIntegerField(default=None, null=True)),
|
||||
('ancestors', models.ManyToManyField(related_name='descendents', through='main.RoleAncestorEntry', to='main.Role')),
|
||||
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType', null=True)),
|
||||
('created_by', models.ForeignKey(related_name="{u'class': 'role', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
|
||||
('members', models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(related_name="{u'class': 'role', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
|
||||
('parents', models.ManyToManyField(related_name='children', to='main.Role')),
|
||||
('implicit_parents', models.TextField(null=False, default=b'[]')),
|
||||
('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_roles',
|
||||
'verbose_name_plural': 'roles',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='roleancestorentry',
|
||||
name='ancestor',
|
||||
field=models.ForeignKey(related_name='+', to='main.Role'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='roleancestorentry',
|
||||
name='descendent',
|
||||
field=models.ForeignKey(related_name='+', to='main.Role'),
|
||||
),
|
||||
migrations.AlterIndexTogether(
|
||||
name='roleancestorentry',
|
||||
index_together=set([('ancestor', 'content_type_id', 'object_id'), ('ancestor', 'content_type_id', 'role_field')]),
|
||||
),
|
||||
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Auditor of the credential', parent_role=[b'singleton:System Auditor'], to='main.Role', role_name=b'Credential Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='owner_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Owner of the credential', parent_role=[b'singleton:System Administrator'], to='main.Role', role_name=b'Credential Owner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this credential, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Credential User', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'CustomInventory Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'CustomInventory Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.member_role', to='main.Role', role_name=b'CustomInventory Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.admin_role', b'parents.admin_role'], to='main.Role', role_name=b'Inventory Group Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.auditor_role', b'parents.auditor_role'], to='main.Role', role_name=b'Inventory Group Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.execute_role', b'parents.executor_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.update_role', b'parents.updater_role'], to='main.Role', role_name=b'Inventory Group Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this inventory', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Inventory Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Inventory Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute jobs against this inventory', parent_role=None, to='main.Role', role_name=b'Inventory Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update the inventory', parent_role=None, to='main.Role', role_name=b'Inventory Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this inventory, but not read sensitive portions or modify it', parent_role=None, to='main.Role', role_name=b'Inventory User', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Full access to all settings', parent_role=[(b'project.admin_role', b'inventory.admin_role')], to='main.Role', role_name=b'Job Template Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read-only access to all settings', parent_role=[(b'project.auditor_role', b'inventory.auditor_role')], to='main.Role', role_name=b'Job Template Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=None, to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage all aspects of this organization', parent_role=b'singleton:System Administrator', to='main.Role', role_name=b'Organization Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this organization', parent_role=b'singleton:System Auditor', to='main.Role', role_name=b'Organization Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this organization', parent_role=b'admin_role', to='main.Role', role_name=b'Organization Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this project', parent_role=[b'organization.admin_role', b'singleton:System Administrator'], to='main.Role', role_name=b'Project Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this project', parent_role=[b'organization.auditor_role', b'singleton:System Auditor'], to='main.Role', role_name=b'Project Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Implies membership within this project', parent_role=None, to='main.Role', role_name=b'Project Member', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='scm_update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update this project from the source control management system', parent_role=b'admin_role', to='main.Role', role_name=b'Project Updater', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May manage this team', parent_role=b'organization.admin_role', to='main.Role', role_name=b'Team Administrator', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read all settings associated with this team', parent_role=b'organization.auditor_role', to='main.Role', role_name=b'Team Auditor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'A member of this team', to='main.Role', role_name=b'Team Member', null=b'True'),
|
||||
),
|
||||
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May read this credential', parent_role=[b'use_role', b'auditor_role', b'owner_role'], to='main.Role', role_name=b'Credential REad', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view but not modify this inventory', parent_role=[b'auditor_role', b'member_role', b'admin_role'], to='main.Role', role_name=b'CustomInventory Read', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute ad hoc commands against this inventory', parent_role=[b'inventory.adhoc_role', b'parents.adhoc_role', b'admin_role'], to='main.Role', role_name=b'Inventory Ad Hoc', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'execute_role', b'update_role', b'auditor_role', b'admin_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute ad hoc commands against this inventory', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory Ad Hoc', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May view this inventory', parent_role=[b'auditor_role', b'execute_role', b'update_role', b'use_role', b'admin_role'], to='main.Role', role_name=b'Read', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=[b'execute_role', b'auditor_role', b'admin_role'], to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read an organization', parent_role=[b'member_role', b'auditor_role'], to='main.Role', role_name=b'Organization Read Access', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Read access to this project', parent_role=[b'member_role', b'auditor_role', b'scm_update_role'], to='main.Role', role_name=b'Project Read Access', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='role_field',
|
||||
field=models.TextField(default=b''),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Can view this team', parent_role=[b'admin_role', b'auditor_role', b'member_role'], to='main.Role', role_name=b'Read', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='credential',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this credential, but not read sensitive portions or modify it', parent_role=[b'owner_role'], to='main.Role', role_name=b'Credential User', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='group',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.execute_role', b'parents.execute_role', b'adhoc_role'], to='main.Role', role_name=b'Inventory Group Executor', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='group',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'', parent_role=[b'inventory.update_role', b'parents.update_role', b'admin_role'], to='main.Role', role_name=b'Inventory Group Updater', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May execute jobs against this inventory', parent_role=b'adhoc_role', to='main.Role', role_name=b'Inventory Executor', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May update the inventory', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory Updater', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May use this inventory, but not read sensitive portions or modify it', parent_role=[b'admin_role'], to='main.Role', role_name=b'Inventory User', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'May run the job template', parent_role=[b'admin_role'], to='main.Role', role_name=b'Job Template Runner', null=b'True'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='project',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', role_description=b'Implies membership within this project', parent_role=b'admin_role', to='main.Role', role_name=b'Project Member', null=b'True'),
|
||||
),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
migrations.RenameField(
|
||||
model_name='organization',
|
||||
old_name='projects',
|
||||
@ -380,4 +86,241 @@ class Migration(migrations.Migration):
|
||||
name='credential',
|
||||
unique_together=set([]),
|
||||
),
|
||||
|
||||
|
||||
#
|
||||
# New RBAC models and fields
|
||||
#
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('role_field', models.TextField()),
|
||||
('singleton_name', models.TextField(default=None, unique=True, null=True, db_index=True)),
|
||||
('members', models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL)),
|
||||
('parents', models.ManyToManyField(related_name='children', to='main.Role')),
|
||||
('implicit_parents', models.TextField(default=b'[]')),
|
||||
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType', null=True)),
|
||||
('object_id', models.PositiveIntegerField(default=None, null=True)),
|
||||
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_roles',
|
||||
'verbose_name_plural': 'roles',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RoleAncestorEntry',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('role_field', models.TextField()),
|
||||
('content_type_id', models.PositiveIntegerField()),
|
||||
('object_id', models.PositiveIntegerField()),
|
||||
('ancestor', models.ForeignKey(related_name='+', to='main.Role')),
|
||||
('descendent', models.ForeignKey(related_name='+', to='main.Role')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'main_rbac_role_ancestors',
|
||||
'verbose_name_plural': 'role_ancestors',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='role',
|
||||
name='ancestors',
|
||||
field=models.ManyToManyField(related_name='descendents', through='main.RoleAncestorEntry', to='main.Role'),
|
||||
),
|
||||
migrations.AlterIndexTogether(
|
||||
name='roleancestorentry',
|
||||
index_together=set([('ancestor', 'content_type_id', 'object_id'), ('ancestor', 'content_type_id', 'role_field'), ('ancestor', 'descendent')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='owner_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_administrator'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'owner_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='credential',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'use_role', b'auditor_role', b'owner_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.auditor_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.member_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='custominventoryscript',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'auditor_role', b'member_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'inventory.admin_role', b'parents.admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'inventory.adhoc_role', b'parents.adhoc_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'inventory.auditor_role', b'parents.auditor_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'inventory.execute_role', b'parents.execute_role', b'adhoc_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'inventory.update_role', b'parents.update_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='group',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'execute_role', b'update_role', b'auditor_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='adhoc_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.auditor_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'adhoc_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='use_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'auditor_role', b'execute_role', b'update_role', b'use_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[(b'project.admin_role', b'inventory.admin_role')], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[(b'project.auditor_role', b'inventory.auditor_role')], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='execute_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobtemplate',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'execute_role', b'auditor_role', b'admin_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'singleton:system_administrator', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'singleton:system_auditor', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'member_role', b'auditor_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'organization.admin_role', b'singleton:system_administrator'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'organization.auditor_role', b'singleton:system_auditor'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='scm_update_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='project',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'member_role', b'auditor_role', b'scm_update_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='admin_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.admin_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='auditor_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=b'organization.auditor_role', to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='member_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=None, to='main.Role', null=b'True'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='read_role',
|
||||
field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'admin_role', b'auditor_role', b'member_role'], to='main.Role', null=b'True'),
|
||||
),
|
||||
]
|
||||
|
@ -44,9 +44,7 @@ def migrate_users(apps, schema_editor):
|
||||
logger.info(smart_text(u"found existing role for user: {}".format(user.username)))
|
||||
except Role.DoesNotExist:
|
||||
role = Role.objects.create(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
singleton_name = smart_text(u'{}-admin_role'.format(user.username)),
|
||||
role_field='admin_role',
|
||||
content_type = user_content_type,
|
||||
object_id = user.id
|
||||
)
|
||||
@ -54,14 +52,12 @@ def migrate_users(apps, schema_editor):
|
||||
logger.info(smart_text(u"migrating to new role for user: {}".format(user.username)))
|
||||
|
||||
if user.is_superuser:
|
||||
if Role.objects.filter(singleton_name='System Administrator').exists():
|
||||
sa_role = Role.objects.get(singleton_name='System Administrator')
|
||||
if Role.objects.filter(singleton_name='system_administrator').exists():
|
||||
sa_role = Role.objects.get(singleton_name='system_administrator')
|
||||
else:
|
||||
sa_role = Role.objects.create(
|
||||
created=now(),
|
||||
modified=now(),
|
||||
singleton_name='System Administrator',
|
||||
name='System Administrator'
|
||||
singleton_name='system_administrator',
|
||||
role_field='system_administrator'
|
||||
)
|
||||
|
||||
sa_role.members.add(user)
|
||||
|
@ -204,27 +204,19 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
help_text=_('Tenant identifier for this credential'),
|
||||
)
|
||||
owner_role = ImplicitRoleField(
|
||||
role_name='Credential Owner',
|
||||
role_description='Owner of the credential',
|
||||
parent_role=[
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
],
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Credential Auditor',
|
||||
role_description='Auditor of the credential',
|
||||
parent_role=[
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
],
|
||||
)
|
||||
use_role = ImplicitRoleField(
|
||||
role_name='Credential User',
|
||||
role_description='May use this credential, but not read sensitive portions or modify it',
|
||||
parent_role=['owner_role']
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Credential REad',
|
||||
role_description='May read this credential',
|
||||
parent_role=[
|
||||
'use_role', 'auditor_role', 'owner_role'
|
||||
],
|
||||
|
@ -97,39 +97,25 @@ class Inventory(CommonModel, ResourceMixin):
|
||||
help_text=_('Number of external inventory sources in this inventory with failures.'),
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Inventory Administrator',
|
||||
role_description='May manage this inventory',
|
||||
parent_role='organization.admin_role',
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Inventory Auditor',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.auditor_role',
|
||||
)
|
||||
update_role = ImplicitRoleField(
|
||||
role_name='Inventory Updater',
|
||||
role_description='May update the inventory',
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
use_role = ImplicitRoleField(
|
||||
role_name='Inventory User',
|
||||
role_description='May use this inventory, but not read sensitive portions or modify it',
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
adhoc_role = ImplicitRoleField(
|
||||
role_name='Inventory Ad Hoc',
|
||||
role_description='May execute ad hoc commands against this inventory',
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Inventory Executor',
|
||||
role_description='May execute jobs against this inventory',
|
||||
parent_role='adhoc_role',
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Read',
|
||||
parent_role=['auditor_role', 'execute_role', 'update_role', 'use_role', 'admin_role'],
|
||||
role_description='May view this inventory',
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
@ -531,28 +517,21 @@ class Group(CommonModelNameNotUnique, ResourceMixin):
|
||||
help_text=_('Inventory source(s) that created or modified this group.'),
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Administrator',
|
||||
parent_role=['inventory.admin_role', 'parents.admin_role'],
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Auditor',
|
||||
parent_role=['inventory.auditor_role', 'parents.auditor_role'],
|
||||
)
|
||||
update_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Updater',
|
||||
parent_role=['inventory.update_role', 'parents.update_role', 'admin_role'],
|
||||
)
|
||||
adhoc_role = ImplicitRoleField(
|
||||
role_name='Inventory Ad Hoc',
|
||||
parent_role=['inventory.adhoc_role', 'parents.adhoc_role', 'admin_role'],
|
||||
role_description='May execute ad hoc commands against this inventory',
|
||||
)
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Executor',
|
||||
parent_role=['inventory.execute_role', 'parents.execute_role', 'adhoc_role'],
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Inventory Group Executor',
|
||||
parent_role=['execute_role', 'update_role', 'auditor_role', 'admin_role'],
|
||||
)
|
||||
|
||||
@ -1321,25 +1300,15 @@ class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin):
|
||||
)
|
||||
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Administrator',
|
||||
role_description='May manage this inventory',
|
||||
parent_role='organization.admin_role',
|
||||
)
|
||||
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Member',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.member_role',
|
||||
)
|
||||
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Auditor',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role='organization.auditor_role',
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='CustomInventory Read',
|
||||
role_description='May view but not modify this inventory',
|
||||
parent_role=['auditor_role', 'member_role', 'admin_role'],
|
||||
)
|
||||
|
||||
|
@ -226,23 +226,15 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
||||
default={},
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Job Template Administrator',
|
||||
role_description='Full access to all settings',
|
||||
parent_role=[('project.admin_role', 'inventory.admin_role')]
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Job Template Auditor',
|
||||
role_description='Read-only access to all settings',
|
||||
parent_role=[('project.auditor_role', 'inventory.auditor_role')]
|
||||
)
|
||||
execute_role = ImplicitRoleField(
|
||||
role_name='Job Template Runner',
|
||||
role_description='May run the job template',
|
||||
parent_role=['admin_role'],
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Job Template Runner',
|
||||
role_description='May run the job template',
|
||||
parent_role=['execute_role', 'auditor_role', 'admin_role'],
|
||||
)
|
||||
|
||||
|
@ -53,23 +53,15 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin):
|
||||
related_name='deprecated_organizations',
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Organization Administrator',
|
||||
role_description='May manage all aspects of this organization',
|
||||
parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Organization Auditor',
|
||||
role_description='May read all settings associated with this organization',
|
||||
parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Organization Member',
|
||||
role_description='A member of this organization',
|
||||
parent_role='admin_role',
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Organization Read Access',
|
||||
role_description='Read an organization',
|
||||
parent_role=['member_role', 'auditor_role'],
|
||||
)
|
||||
|
||||
@ -110,22 +102,13 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
|
||||
related_name='deprecated_teams',
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Team Administrator',
|
||||
role_description='May manage this team',
|
||||
parent_role='organization.admin_role',
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Team Auditor',
|
||||
role_description='May read all settings associated with this team',
|
||||
parent_role='organization.auditor_role',
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Team Member',
|
||||
role_description='A member of this team',
|
||||
)
|
||||
member_role = ImplicitRoleField()
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Read',
|
||||
role_description='Can view this team',
|
||||
parent_role=['admin_role', 'auditor_role', 'member_role'],
|
||||
)
|
||||
|
||||
|
@ -221,34 +221,24 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin):
|
||||
blank=True,
|
||||
)
|
||||
admin_role = ImplicitRoleField(
|
||||
role_name='Project Administrator',
|
||||
role_description='May manage this project',
|
||||
parent_role=[
|
||||
'organization.admin_role',
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
|
||||
],
|
||||
)
|
||||
auditor_role = ImplicitRoleField(
|
||||
role_name='Project Auditor',
|
||||
role_description='May read all settings associated with this project',
|
||||
parent_role=[
|
||||
'organization.auditor_role',
|
||||
'singleton:' + ROLE_SINGLETON_SYSTEM_AUDITOR,
|
||||
],
|
||||
)
|
||||
member_role = ImplicitRoleField(
|
||||
role_name='Project Member',
|
||||
role_description='Implies membership within this project',
|
||||
parent_role='admin_role',
|
||||
)
|
||||
scm_update_role = ImplicitRoleField(
|
||||
role_name='Project Updater',
|
||||
role_description='May update this project from the source control management system',
|
||||
parent_role='admin_role',
|
||||
)
|
||||
read_role = ImplicitRoleField(
|
||||
role_name='Project Read Access',
|
||||
role_description='Read access to this project',
|
||||
parent_role=['member_role', 'auditor_role', 'scm_update_role'],
|
||||
)
|
||||
|
||||
|
@ -29,8 +29,39 @@ __all__ = [
|
||||
|
||||
logger = logging.getLogger('awx.main.models.rbac')
|
||||
|
||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR='System Administrator'
|
||||
ROLE_SINGLETON_SYSTEM_AUDITOR='System Auditor'
|
||||
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR='system_administrator'
|
||||
ROLE_SINGLETON_SYSTEM_AUDITOR='system_auditor'
|
||||
|
||||
role_names = {
|
||||
'system_administrator' : 'System Administrator',
|
||||
'system_auditor' : 'System Auditor',
|
||||
'adhoc_role' : 'Ad Hoc',
|
||||
'admin_role' : 'Admin',
|
||||
'auditor_role' : 'Auditor',
|
||||
'execute_role' : 'Execute',
|
||||
'member_role' : 'Member',
|
||||
'owner_role' : 'Owner',
|
||||
'read_role' : 'Read',
|
||||
'scm_update_role' : 'SCM Update',
|
||||
'update_role' : 'Update',
|
||||
'use_role' : 'Use',
|
||||
}
|
||||
|
||||
role_descriptions = {
|
||||
'system_administrator' : '[TODO] System Administrator',
|
||||
'system_auditor' : '[TODO] System Auditor',
|
||||
'adhoc_role' : '[TODO] Ad Hoc',
|
||||
'admin_role' : '[TODO] Admin',
|
||||
'auditor_role' : '[TODO] Auditor',
|
||||
'execute_role' : '[TODO] Execute',
|
||||
'member_role' : '[TODO] Member',
|
||||
'owner_role' : '[TODO] Owner',
|
||||
'read_role' : '[TODO] Read',
|
||||
'scm_update_role' : '[TODO] SCM Update',
|
||||
'update_role' : '[TODO] Update',
|
||||
'use_role' : '[TODO] Use',
|
||||
}
|
||||
|
||||
|
||||
tls = threading.local() # thread local storage
|
||||
|
||||
@ -51,23 +82,22 @@ def batch_role_ancestor_rebuilding(allow_nesting=False):
|
||||
try:
|
||||
setattr(tls, 'batch_role_rebuilding', True)
|
||||
if not batch_role_rebuilding:
|
||||
setattr(tls, 'roles_needing_rebuilding', set())
|
||||
setattr(tls, 'additions', set())
|
||||
setattr(tls, 'removals', set())
|
||||
yield
|
||||
|
||||
finally:
|
||||
setattr(tls, 'batch_role_rebuilding', batch_role_rebuilding)
|
||||
if not batch_role_rebuilding:
|
||||
rebuild_set = getattr(tls, 'roles_needing_rebuilding')
|
||||
additions = getattr(tls, 'additions')
|
||||
removals = getattr(tls, 'removals')
|
||||
with transaction.atomic():
|
||||
Role._simultaneous_ancestry_rebuild(list(rebuild_set))
|
||||
|
||||
#for role in Role.objects.filter(id__in=list(rebuild_set)).all():
|
||||
# # TODO: We can reduce this to one rebuild call with our new upcoming rebuild method.. do this
|
||||
# role.rebuild_role_ancestor_list()
|
||||
delattr(tls, 'roles_needing_rebuilding')
|
||||
Role.rebuild_role_ancestor_list(list(additions), list(removals))
|
||||
delattr(tls, 'additions')
|
||||
delattr(tls, 'removals')
|
||||
|
||||
|
||||
class Role(CommonModelNameNotUnique):
|
||||
class Role(models.Model):
|
||||
'''
|
||||
Role model
|
||||
'''
|
||||
@ -77,8 +107,8 @@ class Role(CommonModelNameNotUnique):
|
||||
verbose_name_plural = _('roles')
|
||||
db_table = 'main_rbac_roles'
|
||||
|
||||
role_field = models.TextField(null=False)
|
||||
singleton_name = models.TextField(null=True, default=None, db_index=True, unique=True)
|
||||
role_field = models.TextField(null=False, default='')
|
||||
parents = models.ManyToManyField('Role', related_name='children')
|
||||
implicit_parents = models.TextField(null=False, default='[]')
|
||||
ancestors = models.ManyToManyField(
|
||||
@ -94,7 +124,7 @@ class Role(CommonModelNameNotUnique):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(Role, self).save(*args, **kwargs)
|
||||
self.rebuild_role_ancestor_list()
|
||||
self.rebuild_role_ancestor_list([self.id], [])
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:role_detail', args=(self.pk,))
|
||||
@ -112,20 +142,36 @@ class Role(CommonModelNameNotUnique):
|
||||
object_id=accessor.id)
|
||||
return self.ancestors.filter(pk__in=roles).exists()
|
||||
|
||||
def rebuild_role_ancestor_list(self):
|
||||
@property
|
||||
def name(self):
|
||||
global role_names
|
||||
return role_names[self.role_field]
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
global role_descriptions
|
||||
return role_descriptions[self.role_field]
|
||||
|
||||
@staticmethod
|
||||
def rebuild_role_ancestor_list(additions, removals):
|
||||
'''
|
||||
Updates our `ancestors` map to accurately reflect all of the ancestors for a role
|
||||
|
||||
You should never need to call this. Signal handlers should be calling
|
||||
this method when the role hierachy changes automatically.
|
||||
|
||||
Note that this method relies on any parents' ancestor list being correct.
|
||||
'''
|
||||
Role._simultaneous_ancestry_rebuild([self.id])
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _simultaneous_ancestry_rebuild(role_ids_to_rebuild):
|
||||
# The ancestry table
|
||||
# =================================================
|
||||
#
|
||||
# The role ancestors table denormalizes the parental relations
|
||||
# between all roles in the system. If you have role A which is a
|
||||
# parent of B which is a parent of C, then the ancestors table will
|
||||
# contain a row noting that B is a descendent of A, and two rows for
|
||||
# denoting that C is a descendent of both A and B. In addition to
|
||||
# storing entries for each descendent relationship, we also store an
|
||||
# entry that states that C is a 'descendent' of itself, C. This makes
|
||||
# usage of this table simple in our queries as it enables us to do
|
||||
# straight joins where we would have to do unions otherwise.
|
||||
#
|
||||
# The simple version of what this function is doing
|
||||
# =================================================
|
||||
@ -163,37 +209,18 @@ class Role(CommonModelNameNotUnique):
|
||||
#
|
||||
# SQL Breakdown
|
||||
# =============
|
||||
# The Role ancestors has three columns, (id, from_role_id, to_role_id)
|
||||
#
|
||||
# id: Unqiue row ID
|
||||
# from_role_id: Descendent role ID
|
||||
# to_role_id: Ancestor role ID
|
||||
#
|
||||
# *NOTE* In addition to mapping roles to parents, there also
|
||||
# always exists must exist an entry where
|
||||
#
|
||||
# from_role_id == role_id == to_role_id
|
||||
#
|
||||
# this makes our joins simple when we go to derive permissions or
|
||||
# accessible objects.
|
||||
#
|
||||
#
|
||||
# We operate under the assumption that our parent's ancestor list is
|
||||
# correct, thus we can always compute what our ancestor list should
|
||||
# be by taking the union of our parent's ancestor lists and adding
|
||||
# our self reference entry from_role_id == role_id == to_role_id
|
||||
# our self reference entry where ancestor_id = descendent_id
|
||||
#
|
||||
# The inner query for the two SQL statements compute this union,
|
||||
# the union of the parent's ancestors and the self referncing entry,
|
||||
# for all roles in the current set of roles to rebuild.
|
||||
# The DELETE query deletes all entries in the ancestor table that
|
||||
# should no longer be there (as determined by the NOT EXISTS query,
|
||||
# which checks to see if the ancestor is still an ancestor of one
|
||||
# or more of our parents)
|
||||
#
|
||||
# The DELETE query uses this to select all entries on disk for the
|
||||
# roles we're dealing with, and removes the entries that are not in
|
||||
# this list.
|
||||
#
|
||||
# The INSERT query uses this to select all entries in the list that
|
||||
# are not in the database yet, and inserts all of the missing
|
||||
# records.
|
||||
# The INSERT query computes the list of what our ancestor maps should
|
||||
# be, and inserts any missing entries.
|
||||
#
|
||||
# Once complete, we select all of the children for the roles we are
|
||||
# working with, this list becomes the new role list we are working
|
||||
@ -205,18 +232,17 @@ class Role(CommonModelNameNotUnique):
|
||||
#
|
||||
#
|
||||
|
||||
if len(role_ids_to_rebuild) == 0:
|
||||
if len(additions) == 0 and len(removals) == 0:
|
||||
return
|
||||
|
||||
global tls
|
||||
batch_role_rebuilding = getattr(tls, 'batch_role_rebuilding', False)
|
||||
|
||||
if batch_role_rebuilding:
|
||||
roles_needing_rebuilding = getattr(tls, 'roles_needing_rebuilding')
|
||||
roles_needing_rebuilding.update(set(role_ids_to_rebuild))
|
||||
getattr(tls, 'additions').update(set(additions))
|
||||
getattr(tls, 'removals').update(set(removals))
|
||||
return
|
||||
|
||||
|
||||
cursor = connection.cursor()
|
||||
loop_ct = 0
|
||||
|
||||
@ -226,85 +252,98 @@ class Role(CommonModelNameNotUnique):
|
||||
'roles_table': Role._meta.db_table,
|
||||
}
|
||||
|
||||
# SQLlite has a 1M sql statement limit.. since the django sqllite
|
||||
# driver isn't letting us pass in the ids through the preferred
|
||||
# parameter binding system, this function exists to obey this.
|
||||
# est max 12 bytes per number, used up to 2 times in a query,
|
||||
# minus 4k of padding for the other parts of the query, leads us
|
||||
# to the magic number of 41496, or 40000 for a nice round number
|
||||
def split_ids_for_sqlite(role_ids):
|
||||
for i in xrange(0, len(role_ids), 999):
|
||||
yield role_ids[i:i + 999]
|
||||
|
||||
while role_ids_to_rebuild:
|
||||
if loop_ct > 1000:
|
||||
raise Exception('Ancestry role rebuilding error: infinite loop detected')
|
||||
loop_ct += 1
|
||||
|
||||
delete_ct = 0
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
DELETE FROM %(ancestors_table)s
|
||||
WHERE descendent_id IN (%(ids)s)
|
||||
AND
|
||||
id NOT IN (
|
||||
SELECT %(ancestors_table)s.id FROM (
|
||||
SELECT parents.from_role_id from_id, ancestors.ancestor_id to_id
|
||||
FROM %(parents_table)s as parents
|
||||
LEFT JOIN %(ancestors_table)s as ancestors
|
||||
ON (parents.to_role_id = ancestors.descendent_id)
|
||||
WHERE parents.from_role_id IN (%(ids)s) AND ancestors.ancestor_id IS NOT NULL
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id from_id, id to_id from %(roles_table)s WHERE id IN (%(ids)s)
|
||||
) new_ancestry_list
|
||||
LEFT JOIN %(ancestors_table)s ON (new_ancestry_list.from_id = %(ancestors_table)s.descendent_id
|
||||
AND new_ancestry_list.to_id = %(ancestors_table)s.ancestor_id)
|
||||
WHERE %(ancestors_table)s.id IS NOT NULL
|
||||
)
|
||||
''' % sql_params)
|
||||
delete_ct += cursor.rowcount
|
||||
|
||||
insert_ct = 0
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
INSERT INTO %(ancestors_table)s (descendent_id, ancestor_id, role_field, content_type_id, object_id)
|
||||
SELECT from_id, to_id, new_ancestry_list.role_field, new_ancestry_list.content_type_id, new_ancestry_list.object_id FROM (
|
||||
SELECT parents.from_role_id from_id,
|
||||
ancestors.ancestor_id to_id,
|
||||
roles.role_field,
|
||||
COALESCE(roles.content_type_id, 0) content_type_id,
|
||||
COALESCE(roles.object_id, 0) object_id
|
||||
FROM %(parents_table)s as parents
|
||||
INNER JOIN %(roles_table)s as roles ON (parents.from_role_id = roles.id)
|
||||
LEFT OUTER JOIN %(ancestors_table)s as ancestors
|
||||
ON (parents.to_role_id = ancestors.descendent_id)
|
||||
WHERE parents.from_role_id IN (%(ids)s) AND ancestors.ancestor_id IS NOT NULL
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id from_id,
|
||||
id to_id,
|
||||
role_field,
|
||||
COALESCE(content_type_id, 0) content_type_id,
|
||||
COALESCE(object_id, 0) object_id
|
||||
from %(roles_table)s WHERE id IN (%(ids)s)
|
||||
) new_ancestry_list
|
||||
LEFT JOIN %(ancestors_table)s ON (new_ancestry_list.from_id = %(ancestors_table)s.descendent_id
|
||||
AND new_ancestry_list.to_id = %(ancestors_table)s.ancestor_id)
|
||||
WHERE %(ancestors_table)s.id IS NULL
|
||||
''' % sql_params)
|
||||
insert_ct += cursor.rowcount
|
||||
|
||||
if insert_ct == 0 and delete_ct == 0:
|
||||
break
|
||||
|
||||
new_role_ids_to_rebuild = set()
|
||||
for ids in split_ids_for_sqlite(role_ids_to_rebuild):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
new_role_ids_to_rebuild.update(set(Role.objects.distinct()
|
||||
.filter(id__in=ids, children__id__isnull=False)
|
||||
.values_list('children__id', flat=True)))
|
||||
role_ids_to_rebuild = list(new_role_ids_to_rebuild)
|
||||
for i in xrange(0, len(role_ids), 40000):
|
||||
yield role_ids[i:i + 40000]
|
||||
|
||||
|
||||
with transaction.atomic():
|
||||
while len(additions) > 0 or len(removals) > 0:
|
||||
if loop_ct > 100:
|
||||
raise Exception('Role ancestry rebuilding error: infinite loop detected')
|
||||
loop_ct += 1
|
||||
|
||||
delete_ct = 0
|
||||
if len(removals) > 0:
|
||||
for ids in split_ids_for_sqlite(removals):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
DELETE FROM %(ancestors_table)s
|
||||
WHERE descendent_id IN (%(ids)s)
|
||||
AND descendent_id != ancestor_id
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM %(parents_table)s as parents
|
||||
INNER JOIN %(ancestors_table)s as inner_ancestors
|
||||
ON (parents.to_role_id = inner_ancestors.descendent_id)
|
||||
WHERE parents.from_role_id = %(ancestors_table)s.descendent_id
|
||||
AND %(ancestors_table)s.ancestor_id = inner_ancestors.ancestor_id
|
||||
)
|
||||
''' % sql_params)
|
||||
|
||||
delete_ct += cursor.rowcount
|
||||
|
||||
insert_ct = 0
|
||||
if len(additions) > 0:
|
||||
for ids in split_ids_for_sqlite(additions):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
cursor.execute('''
|
||||
INSERT INTO %(ancestors_table)s (descendent_id, ancestor_id, role_field, content_type_id, object_id)
|
||||
SELECT from_id, to_id, new_ancestry_list.role_field, new_ancestry_list.content_type_id, new_ancestry_list.object_id FROM (
|
||||
SELECT roles.id from_id,
|
||||
ancestors.ancestor_id to_id,
|
||||
roles.role_field,
|
||||
COALESCE(roles.content_type_id, 0) content_type_id,
|
||||
COALESCE(roles.object_id, 0) object_id
|
||||
FROM %(roles_table)s as roles
|
||||
INNER JOIN %(parents_table)s as parents
|
||||
ON (parents.from_role_id = roles.id)
|
||||
INNER JOIN %(ancestors_table)s as ancestors
|
||||
ON (parents.to_role_id = ancestors.descendent_id)
|
||||
WHERE roles.id IN (%(ids)s)
|
||||
|
||||
UNION
|
||||
|
||||
SELECT id from_id,
|
||||
id to_id,
|
||||
role_field,
|
||||
COALESCE(content_type_id, 0) content_type_id,
|
||||
COALESCE(object_id, 0) object_id
|
||||
from %(roles_table)s WHERE id IN (%(ids)s)
|
||||
) new_ancestry_list
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM %(ancestors_table)s
|
||||
WHERE %(ancestors_table)s.descendent_id = new_ancestry_list.from_id
|
||||
AND %(ancestors_table)s.ancestor_id = new_ancestry_list.to_id
|
||||
)
|
||||
|
||||
''' % sql_params)
|
||||
insert_ct += cursor.rowcount
|
||||
|
||||
if insert_ct == 0 and delete_ct == 0:
|
||||
break
|
||||
|
||||
new_additions = set()
|
||||
for ids in split_ids_for_sqlite(additions):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
# get all children for the roles we're operating on
|
||||
cursor.execute('SELECT DISTINCT from_role_id FROM %(parents_table)s WHERE to_role_id IN (%(ids)s)' % sql_params)
|
||||
new_additions.update([row[0] for row in cursor.fetchall()])
|
||||
additions = list(new_additions)
|
||||
|
||||
new_removals = set()
|
||||
for ids in split_ids_for_sqlite(removals):
|
||||
sql_params['ids'] = ','.join(str(x) for x in ids)
|
||||
# get all children for the roles we're operating on
|
||||
cursor.execute('SELECT DISTINCT from_role_id FROM %(parents_table)s WHERE to_role_id IN (%(ids)s)' % sql_params)
|
||||
new_removals.update([row[0] for row in cursor.fetchall()])
|
||||
removals = list(new_removals)
|
||||
|
||||
|
||||
@staticmethod
|
||||
@ -313,7 +352,7 @@ class Role(CommonModelNameNotUnique):
|
||||
|
||||
@staticmethod
|
||||
def singleton(name):
|
||||
role, _ = Role.objects.get_or_create(singleton_name=name, name=name)
|
||||
role, _ = Role.objects.get_or_create(singleton_name=name, role_field=name)
|
||||
return role
|
||||
|
||||
def is_ancestor_of(self, role):
|
||||
@ -328,6 +367,7 @@ class RoleAncestorEntry(models.Model):
|
||||
index_together = [
|
||||
("ancestor", "content_type_id", "object_id"), # used by get_roles_on_resource
|
||||
("ancestor", "content_type_id", "role_field"), # used by accessible_objects
|
||||
("ancestor", "descendent"), # used by rebuild_role_ancestor_list in the NOT EXISTS clauses.
|
||||
]
|
||||
|
||||
descendent = models.ForeignKey(Role, null=False, on_delete=models.CASCADE, related_name='+')
|
||||
|
@ -108,12 +108,17 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs):
|
||||
|
||||
def rebuild_role_ancestor_list(reverse, model, instance, pk_set, action, **kwargs):
|
||||
'When a role parent is added or removed, update our role hierarchy list'
|
||||
if action in ['post_add', 'post_remove', 'post_clear']:
|
||||
if action == 'post_add':
|
||||
if reverse:
|
||||
for id in pk_set:
|
||||
model.objects.get(id=id).rebuild_role_ancestor_list()
|
||||
model.rebuild_role_ancestor_list(list(pk_set), [])
|
||||
else:
|
||||
instance.rebuild_role_ancestor_list()
|
||||
model.rebuild_role_ancestor_list([instance.id], [])
|
||||
|
||||
if action in ['post_remove', 'post_clear']:
|
||||
if reverse:
|
||||
model.rebuild_role_ancestor_list([], list(pk_set))
|
||||
else:
|
||||
model.rebuild_role_ancestor_list([], [instance.id])
|
||||
|
||||
def sync_superuser_status_to_rbac(instance, **kwargs):
|
||||
'When the is_superuser flag is changed on a user, reflect that in the membership of the System Admnistrator role'
|
||||
@ -127,11 +132,10 @@ def create_user_role(instance, **kwargs):
|
||||
Role.objects.get(
|
||||
content_type=ContentType.objects.get_for_model(instance),
|
||||
object_id=instance.id,
|
||||
name = 'User Admin'
|
||||
role_field='admin_role'
|
||||
)
|
||||
except Role.DoesNotExist:
|
||||
role = Role.objects.create(
|
||||
name = 'User Admin',
|
||||
role_field='admin_role',
|
||||
content_object = instance,
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from awx.main.models import Role
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_indirect_access_list(get, organization, project, team_factory, user, admin):
|
||||
@ -53,5 +54,5 @@ def test_indirect_access_list(get, organization, project, team_factory, user, ad
|
||||
assert org_admin_team_member_entry['team_name'] == org_admin_team.name
|
||||
|
||||
admin_entry = admin_res['summary_fields']['indirect_access'][0]['role']
|
||||
assert admin_entry['name'] == 'System Administrator'
|
||||
assert admin_entry['name'] == Role.singleton('system_administrator').name
|
||||
|
||||
|
@ -36,7 +36,6 @@ from awx.main.models.organization import (
|
||||
Team,
|
||||
)
|
||||
|
||||
from awx.main.models.rbac import Role
|
||||
from awx.main.models.notifications import Notifier
|
||||
|
||||
'''
|
||||
@ -193,11 +192,6 @@ def notifier(organization):
|
||||
notification_type="webhook",
|
||||
notification_configuration=dict(url="http://localhost",
|
||||
headers={"Test": "Header"}))
|
||||
|
||||
@pytest.fixture
|
||||
def role():
|
||||
return Role.objects.create(name='role')
|
||||
|
||||
@pytest.fixture
|
||||
def admin(user):
|
||||
return user('admin', True)
|
||||
|
@ -10,6 +10,10 @@ def mock_feature_enabled(feature, bypass_database=None):
|
||||
|
||||
#@mock.patch('awx.api.views.feature_enabled', new=mock_feature_enabled)
|
||||
|
||||
@pytest.fixture
|
||||
def role():
|
||||
return Role.objects.create()
|
||||
|
||||
|
||||
#
|
||||
# /roles
|
||||
@ -85,7 +89,7 @@ def test_get_user_roles_list(get, admin):
|
||||
response = get(url, admin)
|
||||
assert response.status_code == 200
|
||||
roles = response.data
|
||||
assert roles['count'] > 0 # 'System Administrator' role if nothing else
|
||||
assert roles['count'] > 0 # 'system_administrator' role if nothing else
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_user_view_other_user_roles(organization, inventory, team, get, alice, bob):
|
||||
|
@ -11,8 +11,8 @@ from awx.main.models import (
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_inheritance_by_children(organization, alice):
|
||||
A = Role.objects.create(name='A', role_field='')
|
||||
B = Role.objects.create(name='B', role_field='')
|
||||
A = Role.objects.create()
|
||||
B = Role.objects.create()
|
||||
A.members.add(alice)
|
||||
|
||||
assert alice not in organization.admin_role
|
||||
@ -38,8 +38,8 @@ def test_auto_inheritance_by_children(organization, alice):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_auto_inheritance_by_parents(organization, alice):
|
||||
A = Role.objects.create(name='A')
|
||||
B = Role.objects.create(name='B')
|
||||
A = Role.objects.create()
|
||||
B = Role.objects.create()
|
||||
A.members.add(alice)
|
||||
|
||||
assert alice not in organization.admin_role
|
||||
@ -58,9 +58,9 @@ def test_auto_inheritance_by_parents(organization, alice):
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_accessible_objects(organization, alice, bob):
|
||||
A = Role.objects.create(name='A')
|
||||
A = Role.objects.create()
|
||||
A.members.add(alice)
|
||||
B = Role.objects.create(name='B')
|
||||
B = Role.objects.create()
|
||||
B.members.add(alice)
|
||||
B.members.add(bob)
|
||||
|
||||
@ -118,7 +118,7 @@ def test_auto_field_adjustments(organization, inventory, team, alice):
|
||||
def test_implicit_deletes(alice):
|
||||
'Ensures implicit resources and roles delete themselves'
|
||||
delorg = Organization.objects.create(name='test-org')
|
||||
child = Role.objects.create(name='child-role')
|
||||
child = Role.objects.create()
|
||||
child.parents.add(delorg.admin_role)
|
||||
delorg.admin_role.members.add(alice)
|
||||
|
||||
@ -129,14 +129,14 @@ def test_implicit_deletes(alice):
|
||||
assert Role.objects.filter(id=admin_role_id).count() == 1
|
||||
assert Role.objects.filter(id=auditor_role_id).count() == 1
|
||||
n_alice_roles = alice.roles.count()
|
||||
n_system_admin_children = Role.singleton('System Administrator').children.count()
|
||||
n_system_admin_children = Role.singleton('system_administrator').children.count()
|
||||
|
||||
delorg.delete()
|
||||
|
||||
assert Role.objects.filter(id=admin_role_id).count() == 0
|
||||
assert Role.objects.filter(id=auditor_role_id).count() == 0
|
||||
assert alice.roles.count() == (n_alice_roles - 1)
|
||||
assert Role.singleton('System Administrator').children.count() == (n_system_admin_children - 1)
|
||||
assert Role.singleton('system_administrator').children.count() == (n_system_admin_children - 1)
|
||||
assert child.ancestors.count() == 1
|
||||
assert child.ancestors.all()[0] == child
|
||||
|
||||
@ -152,11 +152,11 @@ def test_content_object(user):
|
||||
def test_hierarchy_rebuilding_multi_path():
|
||||
'Tests a subdtle cases around role hierarchy rebuilding when you have multiple paths to the same role of different length'
|
||||
|
||||
X = Role.objects.create(name='X')
|
||||
A = Role.objects.create(name='A')
|
||||
B = Role.objects.create(name='B')
|
||||
C = Role.objects.create(name='C')
|
||||
D = Role.objects.create(name='D')
|
||||
X = Role.objects.create()
|
||||
A = Role.objects.create()
|
||||
B = Role.objects.create()
|
||||
C = Role.objects.create()
|
||||
D = Role.objects.create()
|
||||
|
||||
A.children.add(B)
|
||||
A.children.add(D)
|
||||
|
@ -148,7 +148,7 @@ def test_project_user_project(user_project, project, user):
|
||||
def test_project_accessible_by_sa(user, project):
|
||||
u = user('systemadmin', is_superuser=True)
|
||||
# This gets setup by a signal, but we want to test the migration which will set this up too, so remove it
|
||||
Role.singleton('System Administrator').members.remove(u)
|
||||
Role.singleton('system_administrator').members.remove(u)
|
||||
|
||||
assert u not in project.read_role
|
||||
rbac.migrate_organization(apps, None)
|
||||
|
@ -13,7 +13,7 @@ def test_user_admin(user_project, project, user):
|
||||
|
||||
joe = user(username, is_superuser = False)
|
||||
admin = user('admin', is_superuser = True)
|
||||
sa = Role.singleton('System Administrator')
|
||||
sa = Role.singleton('system_administrator')
|
||||
|
||||
# this should happen automatically with our signal
|
||||
assert sa.members.filter(id=admin.id).exists() is True
|
||||
|
@ -114,8 +114,8 @@ class Rollback(Exception):
|
||||
|
||||
try:
|
||||
|
||||
with batch_role_ancestor_rebuilding():
|
||||
with transaction.atomic():
|
||||
with transaction.atomic():
|
||||
with batch_role_ancestor_rebuilding():
|
||||
admin, _ = User.objects.get_or_create(username = 'admin', is_superuser=True)
|
||||
org_admin, _ = User.objects.get_or_create(username = 'org_admin')
|
||||
org_member, _ = User.objects.get_or_create(username = 'org_member')
|
||||
|
Loading…
Reference in New Issue
Block a user