summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--awx/main/migrations/_dab_rbac.py7
-rw-r--r--awx/main/models/rbac.py28
-rw-r--r--awx/main/tests/functional/api/test_credential.py4
-rw-r--r--awx/main/tests/functional/conftest.py8
-rw-r--r--awx/main/tests/functional/dab_rbac/conftest.py10
-rw-r--r--awx/main/tests/functional/dab_rbac/test_dab_migration.py45
-rw-r--r--awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py10
-rw-r--r--awx/main/tests/functional/dab_rbac/test_translation_layer.py50
-rw-r--r--awx/main/tests/functional/test_rbac_job_templates.py2
-rw-r--r--awx/settings/defaults.py9
10 files changed, 85 insertions, 88 deletions
diff --git a/awx/main/migrations/_dab_rbac.py b/awx/main/migrations/_dab_rbac.py
index f97c80e29a..5082a72e4f 100644
--- a/awx/main/migrations/_dab_rbac.py
+++ b/awx/main/migrations/_dab_rbac.py
@@ -275,7 +275,12 @@ def setup_managed_role_definitions(apps, schema_editor):
"""
Idepotent method to create or sync the managed role definitions
"""
- to_create = settings.ANSIBLE_BASE_ROLE_PRECREATE
+ to_create = {
+ 'object_admin': '{cls.__name__} Admin',
+ 'org_admin': 'Organization Admin',
+ 'org_children': 'Organization {cls.__name__} Admin',
+ 'special': '{cls.__name__} {action}',
+ }
ContentType = apps.get_model('contenttypes', 'ContentType')
Permission = apps.get_model('dab_rbac', 'DABPermission')
diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py
index c3cdeb5f6b..3dfb583b42 100644
--- a/awx/main/models/rbac.py
+++ b/awx/main/models/rbac.py
@@ -10,6 +10,9 @@ import re
# django-rest-framework
from rest_framework.serializers import ValidationError
+# crum to impersonate users
+from crum import impersonate
+
# Django
from django.db import models, transaction, connection
from django.db.models.signals import m2m_changed
@@ -553,17 +556,22 @@ def get_role_definition(role):
return
f = obj._meta.get_field(role.role_field)
action_name = f.name.rsplit("_", 1)[0]
- rd_name = f'{type(obj).__name__} {action_name.title()} Compat'
+ model_print = type(obj).__name__
+ rd_name = f'{model_print} {action_name.title()} Compat'
perm_list = get_role_codenames(role)
- defaults = {'content_type_id': role.content_type_id}
- try:
- rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
- except ValidationError:
- # This is a tricky case - practically speaking, users should not be allowed to create team roles
- # or roles that include the team member permission.
- # If we need to create this for compatibility purposes then we will create it as a managed non-editable role
- defaults['managed'] = True
- rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
+ defaults = {
+ 'content_type_id': role.content_type_id,
+ 'description': f'Has {action_name.title()} permission to {model_print} for backwards API compatibility',
+ }
+ with impersonate(None):
+ try:
+ rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
+ except ValidationError:
+ # This is a tricky case - practically speaking, users should not be allowed to create team roles
+ # or roles that include the team member permission.
+ # If we need to create this for compatibility purposes then we will create it as a managed non-editable role
+ defaults['managed'] = True
+ rd, created = RoleDefinition.objects.get_or_create(name=rd_name, permissions=perm_list, defaults=defaults)
return rd
diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py
index f958894702..65e8074241 100644
--- a/awx/main/tests/functional/api/test_credential.py
+++ b/awx/main/tests/functional/api/test_credential.py
@@ -30,7 +30,7 @@ def test_idempotent_credential_type_setup():
@pytest.mark.django_db
-def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh):
+def test_create_user_credential_via_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles):
params = {
'credential_type': 1,
'inputs': {'username': 'someusername'},
@@ -81,7 +81,7 @@ def test_credential_validation_error_with_multiple_owner_fields(post, admin, ali
@pytest.mark.django_db
-def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh):
+def test_create_user_credential_via_user_credentials_list(post, get, alice, credentialtype_ssh, setup_managed_roles):
params = {
'credential_type': 1,
'inputs': {'username': 'someusername'},
diff --git a/awx/main/tests/functional/conftest.py b/awx/main/tests/functional/conftest.py
index 8c68bd91ee..abecda397e 100644
--- a/awx/main/tests/functional/conftest.py
+++ b/awx/main/tests/functional/conftest.py
@@ -16,6 +16,8 @@ from django.db.backends.sqlite3.base import SQLiteCursorWrapper
from django.db.models.signals import post_migrate
+from awx.main.migrations._dab_rbac import setup_managed_role_definitions
+
# AWX
from awx.main.models.projects import Project
from awx.main.models.ha import Instance
@@ -91,6 +93,12 @@ def deploy_jobtemplate(project, inventory, credential):
@pytest.fixture
+def setup_managed_roles():
+ "Run the migration script to pre-create managed role definitions"
+ setup_managed_role_definitions(apps, None)
+
+
+@pytest.fixture
def team(organization):
return organization.teams.create(name='test-team')
diff --git a/awx/main/tests/functional/dab_rbac/conftest.py b/awx/main/tests/functional/dab_rbac/conftest.py
deleted file mode 100644
index 2e37b7f751..0000000000
--- a/awx/main/tests/functional/dab_rbac/conftest.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import pytest
-from django.apps import apps
-
-from awx.main.migrations._dab_rbac import setup_managed_role_definitions
-
-
-@pytest.fixture
-def managed_roles():
- "Run the migration script to pre-create managed role definitions"
- setup_managed_role_definitions(apps, None)
diff --git a/awx/main/tests/functional/dab_rbac/test_dab_migration.py b/awx/main/tests/functional/dab_rbac/test_dab_migration.py
deleted file mode 100644
index 34639774db..0000000000
--- a/awx/main/tests/functional/dab_rbac/test_dab_migration.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import pytest
-from django.apps import apps
-from django.test.utils import override_settings
-
-from awx.main.migrations._dab_rbac import setup_managed_role_definitions
-
-from ansible_base.rbac.models import RoleDefinition
-
-INVENTORY_OBJ_PERMISSIONS = ['view_inventory', 'adhoc_inventory', 'use_inventory', 'change_inventory', 'delete_inventory', 'update_inventory']
-
-
-@pytest.mark.django_db
-def test_managed_definitions_precreate():
- with override_settings(
- ANSIBLE_BASE_ROLE_PRECREATE={
- 'object_admin': '{cls._meta.model_name}-admin',
- 'org_admin': 'organization-admin',
- 'org_children': 'organization-{cls._meta.model_name}-admin',
- 'special': '{cls._meta.model_name}-{action}',
- }
- ):
- setup_managed_role_definitions(apps, None)
- rd = RoleDefinition.objects.get(name='inventory-admin')
- assert rd.managed is True
- # add permissions do not go in the object-level admin
- assert set(rd.permissions.values_list('codename', flat=True)) == set(INVENTORY_OBJ_PERMISSIONS)
-
- # test org-level object admin permissions
- rd = RoleDefinition.objects.get(name='organization-inventory-admin')
- assert rd.managed is True
- assert set(rd.permissions.values_list('codename', flat=True)) == set(['add_inventory', 'view_organization'] + INVENTORY_OBJ_PERMISSIONS)
-
-
-@pytest.mark.django_db
-def test_managed_definitions_custom_obj_admin_name():
- with override_settings(
- ANSIBLE_BASE_ROLE_PRECREATE={
- 'object_admin': 'foo-{cls._meta.model_name}-foo',
- }
- ):
- setup_managed_role_definitions(apps, None)
- rd = RoleDefinition.objects.get(name='foo-inventory-foo')
- assert rd.managed is True
- # add permissions do not go in the object-level admin
- assert set(rd.permissions.values_list('codename', flat=True)) == set(INVENTORY_OBJ_PERMISSIONS)
diff --git a/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py b/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py
index 20041eebd3..d9e3453ef2 100644
--- a/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py
+++ b/awx/main/tests/functional/dab_rbac/test_dab_rbac_api.py
@@ -10,7 +10,7 @@ from ansible_base.rbac.models import RoleDefinition
@pytest.mark.django_db
-def test_managed_roles_created(managed_roles):
+def test_managed_roles_created(setup_managed_roles):
"Managed RoleDefinitions are created in post_migration signal, we expect to see them here"
for cls in (JobTemplate, Inventory):
ct = ContentType.objects.get_for_model(cls)
@@ -22,7 +22,7 @@ def test_managed_roles_created(managed_roles):
@pytest.mark.django_db
-def test_custom_read_role(admin_user, post, managed_roles):
+def test_custom_read_role(admin_user, post, setup_managed_roles):
rd_url = django_reverse('roledefinition-list')
resp = post(
url=rd_url, data={"name": "read role made for test", "content_type": "awx.inventory", "permissions": ['view_inventory']}, user=admin_user, expect=201
@@ -40,7 +40,7 @@ def test_custom_system_roles_prohibited(admin_user, post):
@pytest.mark.django_db
-def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post, managed_roles):
+def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post, setup_managed_roles):
"Alice can not see rando, and so can not give them a role assignment"
rd = RoleDefinition.objects.get(name='Inventory Admin')
rd.give_permission(alice, inventory)
@@ -51,7 +51,7 @@ def test_assignment_to_invisible_user(admin_user, alice, rando, inventory, post,
@pytest.mark.django_db
-def test_assign_managed_role(admin_user, alice, rando, inventory, post, managed_roles, organization):
+def test_assign_managed_role(admin_user, alice, rando, inventory, post, setup_managed_roles, organization):
rd = RoleDefinition.objects.get(name='Inventory Admin')
rd.give_permission(alice, inventory)
# When alice and rando are members of the same org, they can see each other
@@ -78,7 +78,7 @@ def test_assign_custom_delete_role(admin_user, rando, inventory, delete, patch):
@pytest.mark.django_db
-def test_assign_custom_add_role(admin_user, rando, organization, post, managed_roles):
+def test_assign_custom_add_role(admin_user, rando, organization, post, setup_managed_roles):
rd, _ = RoleDefinition.objects.get_or_create(
name='inventory-add', permissions=['add_inventory', 'view_organization'], content_type=ContentType.objects.get_for_model(Organization)
)
diff --git a/awx/main/tests/functional/dab_rbac/test_translation_layer.py b/awx/main/tests/functional/dab_rbac/test_translation_layer.py
index 2829599252..c8e529c902 100644
--- a/awx/main/tests/functional/dab_rbac/test_translation_layer.py
+++ b/awx/main/tests/functional/dab_rbac/test_translation_layer.py
@@ -2,11 +2,15 @@ from unittest import mock
import pytest
+from django.contrib.contenttypes.models import ContentType
+
+from crum import impersonate
+
from awx.main.models.rbac import get_role_from_object_role, give_creator_permissions
from awx.main.models import User, Organization, WorkflowJobTemplate, WorkflowJobTemplateNode, Team
from awx.api.versioning import reverse
-from ansible_base.rbac.models import RoleUserAssignment
+from ansible_base.rbac.models import RoleUserAssignment, RoleDefinition
@pytest.mark.django_db
@@ -14,7 +18,7 @@ from ansible_base.rbac.models import RoleUserAssignment
'role_name',
['execution_environment_admin_role', 'project_admin_role', 'admin_role', 'auditor_role', 'read_role', 'execute_role', 'notification_admin_role'],
)
-def test_round_trip_roles(organization, rando, role_name, managed_roles):
+def test_round_trip_roles(organization, rando, role_name, setup_managed_roles):
"""
Make an assignment with the old-style role,
get the equivelent new role
@@ -28,7 +32,39 @@ def test_round_trip_roles(organization, rando, role_name, managed_roles):
@pytest.mark.django_db
-def test_organization_level_permissions(organization, inventory, managed_roles):
+def test_role_naming(setup_managed_roles):
+ qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='dmin')
+ assert qs.count() == 1 # sanity
+ rd = qs.first()
+ assert rd.name == 'JobTemplate Admin'
+ assert rd.description
+ assert rd.created_by is None
+
+
+@pytest.mark.django_db
+def test_action_role_naming(setup_managed_roles):
+ qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='ecute')
+ assert qs.count() == 1 # sanity
+ rd = qs.first()
+ assert rd.name == 'JobTemplate Execute'
+ assert rd.description
+ assert rd.created_by is None
+
+
+@pytest.mark.django_db
+def test_compat_role_naming(setup_managed_roles, job_template, rando, alice):
+ with impersonate(alice):
+ job_template.read_role.members.add(rando)
+ qs = RoleDefinition.objects.filter(content_type=ContentType.objects.get(model='jobtemplate'), name__endswith='ompat')
+ assert qs.count() == 1 # sanity
+ rd = qs.first()
+ assert rd.name == 'JobTemplate Read Compat'
+ assert rd.description
+ assert rd.created_by is None
+
+
+@pytest.mark.django_db
+def test_organization_level_permissions(organization, inventory, setup_managed_roles):
u1 = User.objects.create(username='alice')
u2 = User.objects.create(username='bob')
@@ -58,14 +94,14 @@ def test_organization_level_permissions(organization, inventory, managed_roles):
@pytest.mark.django_db
-def test_organization_execute_role(organization, rando, managed_roles):
+def test_organization_execute_role(organization, rando, setup_managed_roles):
organization.execute_role.members.add(rando)
assert rando in organization.execute_role
assert set(Organization.accessible_objects(rando, 'execute_role')) == set([organization])
@pytest.mark.django_db
-def test_workflow_approval_list(get, post, admin_user, managed_roles):
+def test_workflow_approval_list(get, post, admin_user, setup_managed_roles):
workflow_job_template = WorkflowJobTemplate.objects.create()
approval_node = WorkflowJobTemplateNode.objects.create(workflow_job_template=workflow_job_template)
url = reverse('api:workflow_job_template_node_create_approval', kwargs={'pk': approval_node.pk, 'version': 'v2'})
@@ -79,14 +115,14 @@ def test_workflow_approval_list(get, post, admin_user, managed_roles):
@pytest.mark.django_db
-def test_creator_permission(rando, admin_user, inventory, managed_roles):
+def test_creator_permission(rando, admin_user, inventory, setup_managed_roles):
give_creator_permissions(rando, inventory)
assert rando in inventory.admin_role
assert rando in inventory.admin_role.members.all()
@pytest.mark.django_db
-def test_team_team_read_role(rando, team, admin_user, post, managed_roles):
+def test_team_team_read_role(rando, team, admin_user, post, setup_managed_roles):
orgs = [Organization.objects.create(name=f'foo-{i}') for i in range(2)]
teams = [Team.objects.create(name=f'foo-{i}', organization=orgs[i]) for i in range(2)]
teams[1].member_role.members.add(rando)
diff --git a/awx/main/tests/functional/test_rbac_job_templates.py b/awx/main/tests/functional/test_rbac_job_templates.py
index 17e7ff3524..0b73dc34cb 100644
--- a/awx/main/tests/functional/test_rbac_job_templates.py
+++ b/awx/main/tests/functional/test_rbac_job_templates.py
@@ -165,7 +165,7 @@ class TestOrphanJobTemplate:
@pytest.mark.django_db
@pytest.mark.job_permissions
-def test_job_template_creator_access(project, organization, rando, post):
+def test_job_template_creator_access(project, organization, rando, post, setup_managed_roles):
project.use_role.members.add(rando)
response = post(
url=reverse('api:job_template_list'),
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index c927086354..5176dc2b84 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -1148,13 +1148,8 @@ ANSIBLE_BASE_CUSTOM_VIEW_PARENT = 'awx.api.generics.APIView'
# Settings for the ansible_base RBAC system
-# Only used internally, names of the managed RoleDefinitions to create
-ANSIBLE_BASE_ROLE_PRECREATE = {
- 'object_admin': '{cls.__name__} Admin',
- 'org_admin': 'Organization Admin',
- 'org_children': 'Organization {cls.__name__} Admin',
- 'special': '{cls.__name__} {action}',
-}
+# This has been moved to data migration code
+ANSIBLE_BASE_ROLE_PRECREATE = {}
# Name for auto-created roles that give users permissions to what they create
ANSIBLE_BASE_ROLE_CREATOR_NAME = '{cls.__name__} Creator'