started access refactoring, added UserAccess and updated how ALL permissions is checked

This commit is contained in:
Wayne Witzel III
2016-02-29 15:36:51 -05:00
parent a4b3567619
commit 380ccec687
5 changed files with 35 additions and 90 deletions

View File

@@ -16,9 +16,9 @@ from rest_framework.exceptions import ParseError, PermissionDenied
# AWX
from awx.main.utils import * # noqa
from awx.main.models import * # noqa
from awx.main.models.rbac import ALL_PERMISSIONS
from awx.api.license import LicenseForbids
from awx.main.task_engine import TaskSerializer
from awx.main.conf import tower_settings
__all__ = ['get_user_queryset', 'check_user_access']
@@ -52,6 +52,21 @@ access_registry = {
# ...
}
def user_or_team(data):
try:
if 'user' in data:
pk = get_pk_from_dict(data, 'user')
return get_object_or_400(User, pk=pk), None
elif 'team' in data:
pk = get_pk_from_dict(data, 'team')
return None, get_object_or_400(Team, pk=pk)
else:
return None, None
except ParseError:
return None, None
def register_access(model_class, access_class):
access_classes = access_registry.setdefault(model_class, [])
access_classes.append(access_class)
@@ -193,24 +208,16 @@ class UserAccess(BaseAccess):
model = User
def get_queryset(self):
qs = self.model.objects.filter(is_active=True).distinct()
if self.user.is_superuser:
return qs
if tower_settings.ORG_ADMINS_CAN_SEE_ALL_USERS and self.user.admin_of_organizations.filter(active=True).exists():
return qs
return qs.filter(
Q(pk=self.user.pk) |
Q(organizations__in=self.user.admin_of_organizations.filter(active=True)) |
Q(organizations__in=self.user.organizations.filter(active=True)) |
Q(teams__in=self.user.teams.filter(active=True))
).distinct()
qs = self.model.accessible_objects(self.user, {'read':True})
return qs
def can_add(self, data):
if data is not None and 'is_superuser' in data:
if to_python_boolean(data['is_superuser'], allow_none=True) and not self.user.is_superuser:
return False
return bool(self.user.is_superuser or
self.user.admin_of_organizations.filter(active=True).exists())
if self.user.is_superuser:
return True
return Organization.accessible_objects(self.user, ALL_PERMISSIONS).filter(active=True).exists()
def can_change(self, obj, data):
if data is not None and 'is_superuser' in data:
@@ -225,7 +232,7 @@ class UserAccess(BaseAccess):
# Admin implies changing all user fields.
if self.user.is_superuser:
return True
return bool(obj.organizations.filter(active=True, admins__in=[self.user]).exists())
return obj.accessible_by(self.user, {'create': True, 'write':True, 'update':True, 'read':True})
def can_delete(self, obj):
if obj == self.user:
@@ -235,8 +242,8 @@ class UserAccess(BaseAccess):
if obj.is_superuser and super_users.count() == 1:
# cannot delete the last active superuser
return False
return bool(self.user.is_superuser or
obj.organizations.filter(active=True, admins__in=[self.user]).exists())
return obj.accessible_by(self.user, {'delete': True})
class OrganizationAccess(BaseAccess):
'''

View File

@@ -51,7 +51,7 @@ class ResourceMixin(models.Model):
'''
perms = self.get_permissions(user)
if not perms:
if perms is None:
return False
for k in permissions:
if k not in perms or perms[k] < permissions[k]:

View File

@@ -18,7 +18,11 @@ from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.fields import AutoOneToOneField, ImplicitRoleField
from awx.main.models.base import * # noqa
from awx.main.models.rbac import ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR
from awx.main.models.rbac import (
ALL_PERMISSIONS,
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
ROLE_SINGLETON_SYSTEM_AUDITOR,
)
from awx.main.models.mixins import ResourceMixin
from awx.main.conf import tower_settings
@@ -52,7 +56,7 @@ class Organization(CommonModel, ResourceMixin):
admin_role = ImplicitRoleField(
role_name='Organization Administrator',
parent_role='singleton:' + ROLE_SINGLETON_SYSTEM_ADMINISTRATOR,
permissions = {'all': True}
permissions = ALL_PERMISSIONS,
)
auditor_role = ImplicitRoleField(
role_name='Organization Auditor',
@@ -108,7 +112,7 @@ class Team(CommonModelNameNotUnique, ResourceMixin):
admin_role = ImplicitRoleField(
role_name='Team Administrator',
parent_role='organization.admin_role',
permissions = {'all': True}
permissions = ALL_PERMISSIONS,
)
auditor_role = ImplicitRoleField(
role_name='Team Auditor',

View File

@@ -31,7 +31,8 @@ ROLE_SINGLETON_SYSTEM_AUDITOR='System Auditor'
role_rebuilding_paused = False
roles_needing_rebuilding = set()
ALL_PERMISSIONS = {'create': True, 'read': True, 'update': True, 'delete': True,
'write': True, 'scm_update': True, 'use': True, 'execute': True}
class Role(CommonModelNameNotUnique):
'''
@@ -122,18 +123,6 @@ class Role(CommonModelNameNotUnique):
def grant(self, resource, permissions):
# take either the raw Resource or something that includes the ResourceMixin
resource = resource if type(resource) is Resource else resource.resource
if 'all' in permissions and permissions['all']:
del permissions['all']
permissions['create'] = True
permissions['read'] = True
permissions['write'] = True
permissions['update'] = True
permissions['delete'] = True
permissions['scm_update'] = True
permissions['use'] = True
permissions['execute'] = True
permission = RolePermission(role=self, resource=resource)
for k in permissions:
setattr(permission, k, int(permissions[k]))
@@ -256,8 +245,8 @@ class RolePermission(CreatedModifiedModel):
create = models.IntegerField(default = 0)
read = models.IntegerField(default = 0)
write = models.IntegerField(default = 0)
update = models.IntegerField(default = 0)
delete = models.IntegerField(default = 0)
update = models.IntegerField(default = 0)
execute = models.IntegerField(default = 0)
scm_update = models.IntegerField(default = 0)
use = models.IntegerField(default = 0)

View File

@@ -130,58 +130,6 @@ def sync_superuser_status_to_rbac(sender, instance, **kwargs):
else:
Role.singleton(ROLE_SINGLETON_SYSTEM_ADMINISTRATOR).members.remove(instance)
def sync_user_to_team_members_role(sender, reverse, model, instance, pk_set, action, **kwargs):
'When a user is added or removed from Team.users, ensure that is reflected in Team.member_role'
if action == 'post_add' or action == 'pre_remove':
if reverse:
for team in Team.objects.filter(id__in=pk_set).all():
if action == 'post_add':
team.member_role.members.add(instance)
if action == 'pre_remove':
team.member_role.members.remove(instance)
else:
for user in User.objects.filter(id__in=pk_set).all():
if action == 'post_add':
instance.member_role.members.add(user)
if action == 'pre_remove':
instance.member_role.members.remove(user)
def sync_admin_to_org_admin_role(sender, reverse, model, instance, pk_set, action, **kwargs):
'When a user is added or removed from Organization.admins, ensure that is reflected in Organization.admin_role'
if action == 'post_add' or action == 'pre_remove':
if reverse:
for org in Organization.objects.filter(id__in=pk_set).all():
if action == 'post_add':
org.admin_role.members.add(instance)
if action == 'pre_remove':
org.admin_role.members.remove(instance)
else:
for user in User.objects.filter(id__in=pk_set).all():
if action == 'post_add':
instance.admin_role.members.add(user)
if action == 'pre_remove':
instance.admin_role.members.remove(user)
def sync_user_to_org_members_role(sender, reverse, model, instance, pk_set, action, **kwargs):
'When a user is added or removed from Organization.users, ensure that is reflected in Organization.member_role'
if action == 'post_add' or action == 'pre_remove':
if reverse:
for org in Organization.objects.filter(id__in=pk_set).all():
if action == 'post_add':
org.member_role.members.add(instance)
org.admin_role.children.add(instance.resource.admin_role)
if action == 'pre_remove':
org.member_role.members.remove(instance)
org.admin_role.children.remove(instance.resource.admin_role)
else:
for user in User.objects.filter(id__in=pk_set).all():
if action == 'post_add':
instance.member_role.members.add(user)
instance.admin_role.children.add(user.resource.admin_role)
if action == 'pre_remove':
instance.member_role.members.remove(user)
instance.admin_role.children.remove(user.resource.admin_role)
def create_user_resource(sender, **kwargs):
instance = kwargs['instance']
try:
@@ -210,10 +158,7 @@ post_save.connect(emit_job_event_detail, sender=JobEvent)
post_save.connect(emit_ad_hoc_command_event_detail, sender=AdHocCommandEvent)
m2m_changed.connect(rebuild_role_ancestor_list, Role.parents.through)
post_save.connect(sync_superuser_status_to_rbac, sender=User)
m2m_changed.connect(sync_user_to_team_members_role, Team.users.through)
post_save.connect(create_user_resource, sender=User)
m2m_changed.connect(sync_user_to_org_members_role, Organization.users.through)
m2m_changed.connect(sync_admin_to_org_admin_role, Organization.admins.through)
# Migrate hosts, groups to parent group(s) whenever a group is deleted or
# marked as inactive.