diff --git a/awx/main/access.py b/awx/main/access.py index 1bc1d90f5f..7e5b3b281a 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -660,7 +660,7 @@ class InventoryAccess(BaseAccess): # Verify that the user has access to the new organization if moving an # inventory to a new organization. Otherwise, just check for admin permission. return ( - self.check_related('organization', Organization, data, obj=obj, + self.check_related('organization', Organization, data, obj=obj, role_field='inventory_admin_role', mandatory=org_admin_mandatory) and self.user in obj.admin_role ) @@ -985,7 +985,8 @@ class CredentialAccess(BaseAccess): return check_user_access(self.user, Team, 'change', team_obj, None) if data and data.get('organization', None): organization_obj = get_object_from_data('organization', Organization, data) - return check_user_access(self.user, Organization, 'change', organization_obj, None) + return any([check_user_access(self.user, Organization, 'change', organization_obj, None), + self.user in organization_obj.credential_admin_role]) return False @check_superuser @@ -1098,7 +1099,7 @@ class ProjectAccess(BaseAccess): @check_superuser def can_change(self, obj, data): - if not self.check_related('organization', Organization, data, obj=obj): + if not self.check_related('organization', Organization, data, obj=obj, role_field='project_admin_role'): return False return self.user in obj.admin_role @@ -1439,7 +1440,7 @@ class JobAccess(BaseAccess): elif not jt_access: return False - org_access = obj.inventory and self.user in obj.inventory.organization.admin_role + org_access = obj.inventory and self.user in obj.inventory.organization.inventory_admin_role project_access = obj.project is None or self.user in obj.project.admin_role credential_access = all([self.user in cred.use_role for cred in obj.credentials.all()]) @@ -2218,8 +2219,7 @@ class NotificationTemplateAccess(BaseAccess): def filtered_queryset(self): return self.model.objects.filter( - Q(organization__in=Organization.objects.filter(notification_admin_role__members=self.user)) | - Q(organization__in=self.user.admin_of_organizations) | + Q(organization__in=Organization.accessible_objects(self.user, 'notification_admin_role')) | Q(organization__in=self.user.auditor_of_organizations) ).distinct() @@ -2266,8 +2266,7 @@ class NotificationAccess(BaseAccess): def filtered_queryset(self): return self.model.objects.filter( - Q(notification_template__organization__in=Organization.objects.filter(notification_admin_role__members=self.user)) | - Q(notification_template__organization__in=self.user.admin_of_organizations) | + Q(notification_template__organization__in=Organization.accessible_objects(self.user, 'notification_admin_role')) | Q(notification_template__organization__in=self.user.auditor_of_organizations) ).distinct() diff --git a/awx/main/migrations/0020_v330_declare_new_rbac_roles.py b/awx/main/migrations/0021_v330_declare_new_rbac_roles.py similarity index 98% rename from awx/main/migrations/0020_v330_declare_new_rbac_roles.py rename to awx/main/migrations/0021_v330_declare_new_rbac_roles.py index 9b489b7b70..a279ef90e3 100644 --- a/awx/main/migrations/0020_v330_declare_new_rbac_roles.py +++ b/awx/main/migrations/0021_v330_declare_new_rbac_roles.py @@ -11,7 +11,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('main', '0019_v330_custom_virtualenv'), + ('main', '0020_v330_instancegroup_policies'), ] operations = [ diff --git a/awx/main/migrations/0021_v330_create_new_rbac_roles.py b/awx/main/migrations/0022_v330_create_new_rbac_roles.py similarity index 90% rename from awx/main/migrations/0021_v330_create_new_rbac_roles.py rename to awx/main/migrations/0022_v330_create_new_rbac_roles.py index fe15c951dd..578be8645c 100644 --- a/awx/main/migrations/0021_v330_create_new_rbac_roles.py +++ b/awx/main/migrations/0022_v330_create_new_rbac_roles.py @@ -10,7 +10,7 @@ from awx.main.migrations import _migration_utils as migration_utils class Migration(ActivityStreamDisabledMigration): dependencies = [ - ('main', '0020_v330_declare_new_rbac_roles'), + ('main', '0021_v330_declare_new_rbac_roles'), ] operations = [ diff --git a/awx/main/models/rbac.py b/awx/main/models/rbac.py index 010d0a624b..930b226ac6 100644 --- a/awx/main/models/rbac.py +++ b/awx/main/models/rbac.py @@ -61,7 +61,10 @@ role_descriptions = { 'workflow_admin_role': _('Can manage all workflows of the %s'), 'notification_admin_role': _('Can manage all notifications of the %s'), 'auditor_role': _('Can view all settings for the %s'), - 'execute_role': _('May run the %s'), + 'execute_role': { + 'organization': _('May run any executable resources in the organization'), + 'default': _('May run the %s'), + }, 'member_role': _('User is a member of the %s'), 'read_role': _('May view settings for the %s'), 'update_role': _('May update project or inventory or group using the configured source update system'), @@ -180,12 +183,22 @@ class Role(models.Model): global role_descriptions description = role_descriptions[self.role_field] content_type = self.content_type - if '%s' in description and content_type: + + model_name = None + if content_type: model = content_type.model_class() model_name = re.sub(r'([a-z])([A-Z])', r'\1 \2', model.__name__).lower() - description = description % model_name - return description + value = description + if type(description) == dict: + value = description.get(model_name) + if value is None: + value = description.get('default') + + if '%s' in value and content_type: + value = value % model_name + + return value @staticmethod def rebuild_role_ancestor_list(additions, removals):