mirror of
https://github.com/ansible/awx.git
synced 2026-07-11 08:18:07 -02:30
Working on surfacing credentials via REST.
This commit is contained in:
@@ -34,7 +34,7 @@ import json as python_json
|
|||||||
# FIXME: machinery for auto-adding audit trail logs to all CREATE/EDITS
|
# FIXME: machinery for auto-adding audit trail logs to all CREATE/EDITS
|
||||||
|
|
||||||
class BaseList(generics.ListCreateAPIView):
|
class BaseList(generics.ListCreateAPIView):
|
||||||
|
|
||||||
def list_permissions_check(self, request, obj=None):
|
def list_permissions_check(self, request, obj=None):
|
||||||
''' determines some early yes/no access decisions, pre-filtering '''
|
''' determines some early yes/no access decisions, pre-filtering '''
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
@@ -50,7 +50,7 @@ class BaseList(generics.ListCreateAPIView):
|
|||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
return True
|
return True
|
||||||
raise exceptions.NotImplementedError
|
raise exceptions.NotImplementedError
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
base = self._get_queryset()
|
base = self._get_queryset()
|
||||||
model = self.__class__.model
|
model = self.__class__.model
|
||||||
@@ -121,11 +121,16 @@ class BaseSubList(BaseList):
|
|||||||
# save the object through the serializer, reload and returned the saved object deserialized
|
# save the object through the serializer, reload and returned the saved object deserialized
|
||||||
obj = ser.save()
|
obj = ser.save()
|
||||||
ser = self.__class__.serializer_class(obj)
|
ser = self.__class__.serializer_class(obj)
|
||||||
|
|
||||||
# now make sure we could have already attached the two together. If we could not have, raise an exception
|
# now make sure we could have already attached the two together. If we could not have, raise an exception
|
||||||
# such that the transaction does not commit.
|
# such that the transaction does not commit.
|
||||||
if not self.__class__.parent_model.can_user_attach(request.user, main, obj, self.__class__.relationship):
|
if self.__class__.parent_model != User:
|
||||||
raise PermissionDenied()
|
if not self.__class__.parent_model.can_user_attach(request.user, main, obj, self.__class__.relationship):
|
||||||
|
raise PermissionDenied()
|
||||||
|
else:
|
||||||
|
# FIXME: should generalize this
|
||||||
|
if not UserHelper.can_user_attach(request.user, main, obj, self.__class__.relationship):
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
return Response(status=status.HTTP_201_CREATED, data=ser.data)
|
return Response(status=status.HTTP_201_CREATED, data=ser.data)
|
||||||
|
|
||||||
@@ -141,7 +146,7 @@ class BaseSubList(BaseList):
|
|||||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||||
sub = subs[0]
|
sub = subs[0]
|
||||||
relationship = getattr(main, self.__class__.relationship)
|
relationship = getattr(main, self.__class__.relationship)
|
||||||
|
|
||||||
if not 'disassociate' in request.DATA:
|
if not 'disassociate' in request.DATA:
|
||||||
if not request.user.is_superuser and not self.__class__.parent_model.can_user_attach(request.user, main, sub, self.__class__.relationship):
|
if not request.user.is_superuser and not self.__class__.parent_model.can_user_attach(request.user, main, sub, self.__class__.relationship):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
@@ -215,14 +220,14 @@ class BaseDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class VariableBaseDetail(BaseDetail):
|
class VariableBaseDetail(BaseDetail):
|
||||||
'''
|
'''
|
||||||
an object that is always 1 to 1 with the foreign key of another object
|
an object that is always 1 to 1 with the foreign key of another object
|
||||||
and does not have it's own key, such as HostVariableDetail
|
and does not have it's own key, such as HostVariableDetail
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
def delete_permissions_check(self, request, obj):
|
def delete_permissions_check(self, request, obj):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
@@ -285,4 +290,4 @@ class VariableBaseDetail(BaseDetail):
|
|||||||
if not has_permission:
|
if not has_permission:
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
return Response(status=status.HTTP_200_OK, data=python_json.loads(this_object.data))
|
return Response(status=status.HTTP_200_OK, data=python_json.loads(this_object.data))
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,13 @@ class UserHelper(object):
|
|||||||
matching_orgs = obj.organizations.filter(admins__in = [user]).count()
|
matching_orgs = obj.organizations.filter(admins__in = [user]).count()
|
||||||
return matching_orgs
|
return matching_orgs
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def can_user_attach(cls, user, obj, sub_obj, relationship_type):
|
||||||
|
if type(sub_obj) != User:
|
||||||
|
if not sub_obj.can_user_read(user, sub_obj):
|
||||||
|
return False
|
||||||
|
rc = cls.can_user_administrate(user, obj)
|
||||||
|
return rc
|
||||||
|
|
||||||
class PrimordialModel(models.Model):
|
class PrimordialModel(models.Model):
|
||||||
'''
|
'''
|
||||||
@@ -186,11 +193,11 @@ class CommonModel(PrimordialModel):
|
|||||||
name = models.CharField(max_length=512, unique=True)
|
name = models.CharField(max_length=512, unique=True)
|
||||||
|
|
||||||
class CommonModelNameNotUnique(PrimordialModel):
|
class CommonModelNameNotUnique(PrimordialModel):
|
||||||
''' a base model where the name is not unique '''
|
''' a base model where the name is not unique '''
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
name = models.CharField(max_length=512, unique=False)
|
name = models.CharField(max_length=512, unique=False)
|
||||||
|
|
||||||
class Tag(models.Model):
|
class Tag(models.Model):
|
||||||
@@ -290,7 +297,7 @@ class Inventory(CommonModel):
|
|||||||
unique_together = (("name", "organization"),)
|
unique_together = (("name", "organization"),)
|
||||||
|
|
||||||
organization = models.ForeignKey(Organization, null=False, related_name='inventories')
|
organization = models.ForeignKey(Organization, null=False, related_name='inventories')
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
import lib.urls
|
import lib.urls
|
||||||
return reverse(lib.urls.views_InventoryDetail, args=(self.pk,))
|
return reverse(lib.urls.views_InventoryDetail, args=(self.pk,))
|
||||||
@@ -308,16 +315,16 @@ class Inventory(CommonModel):
|
|||||||
user = user,
|
user = user,
|
||||||
permission_type__in = allowed
|
permission_type__in = allowed
|
||||||
).count()
|
).count()
|
||||||
|
|
||||||
result = (by_org_admin + by_team_permission + by_user_permission)
|
result = (by_org_admin + by_team_permission + by_user_permission)
|
||||||
return result > 0
|
return result > 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _has_any_inventory_permission_types(cls, user, allowed):
|
def _has_any_inventory_permission_types(cls, user, allowed):
|
||||||
'''
|
'''
|
||||||
rather than checking for a permission on a specific inventory, return whether we have
|
rather than checking for a permission on a specific inventory, return whether we have
|
||||||
permissions on any inventory. This is primarily used to decide if the user can create
|
permissions on any inventory. This is primarily used to decide if the user can create
|
||||||
host or group objects
|
host or group objects
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
@@ -332,7 +339,7 @@ class Inventory(CommonModel):
|
|||||||
by_user_permission = user.permissions.filter(
|
by_user_permission = user.permissions.filter(
|
||||||
permission_type__in = allowed
|
permission_type__in = allowed
|
||||||
).count()
|
).count()
|
||||||
|
|
||||||
result = (by_org_admin + by_team_permission + by_user_permission)
|
result = (by_org_admin + by_team_permission + by_user_permission)
|
||||||
return result > 0
|
return result > 0
|
||||||
|
|
||||||
@@ -380,7 +387,7 @@ class Host(CommonModelNameNotUnique):
|
|||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
unique_together = (("name", "inventory"),)
|
unique_together = (("name", "inventory"),)
|
||||||
|
|
||||||
variable_data = models.OneToOneField('VariableData', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='host')
|
variable_data = models.OneToOneField('VariableData', null=True, default=None, blank=True, on_delete=SET_NULL, related_name='host')
|
||||||
inventory = models.ForeignKey('Inventory', null=False, related_name='hosts')
|
inventory = models.ForeignKey('Inventory', null=False, related_name='hosts')
|
||||||
|
|
||||||
@@ -390,7 +397,7 @@ class Host(CommonModelNameNotUnique):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def can_user_read(cls, user, obj):
|
def can_user_read(cls, user, obj):
|
||||||
return Inventory.can_user_read(user, obj.inventory)
|
return Inventory.can_user_read(user, obj.inventory)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_user_add(cls, user, data):
|
def can_user_add(cls, user, data):
|
||||||
if not 'inventory' in data:
|
if not 'inventory' in data:
|
||||||
@@ -432,7 +439,7 @@ class Group(CommonModelNameNotUnique):
|
|||||||
inventory = Inventory.objects.get(pk=data['inventory'])
|
inventory = Inventory.objects.get(pk=data['inventory'])
|
||||||
return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
|
return Inventory._has_permission_types(user, inventory, PERMISSION_TYPES_ALLOWING_INVENTORY_WRITE)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_user_administrate(cls, user, obj):
|
def can_user_administrate(cls, user, obj):
|
||||||
# here this controls whether the user can attach subgroups
|
# here this controls whether the user can attach subgroups
|
||||||
@@ -511,7 +518,7 @@ class Credential(CommonModel):
|
|||||||
#
|
#
|
||||||
# STAGE 3:
|
# STAGE 3:
|
||||||
#
|
#
|
||||||
# MICHAEL: modify ansible/ansible-playbook such that
|
# MICHAEL: modify ansible/ansible-playbook such that
|
||||||
# if ANSIBLE_PASSWORD or ANSIBLE_SUDO_PASSWORD is set
|
# if ANSIBLE_PASSWORD or ANSIBLE_SUDO_PASSWORD is set
|
||||||
# you do not have to use --ask-pass and --ask-sudo-pass, so we don't have to do interactive
|
# you do not have to use --ask-pass and --ask-sudo-pass, so we don't have to do interactive
|
||||||
# stuff with that.
|
# stuff with that.
|
||||||
@@ -520,10 +527,24 @@ class Credential(CommonModel):
|
|||||||
|
|
||||||
ssh_key_data = models.TextField(blank=True, default='')
|
ssh_key_data = models.TextField(blank=True, default='')
|
||||||
ssh_key_unlock = models.CharField(blank=True, default='', max_length=1024)
|
ssh_key_unlock = models.CharField(blank=True, default='', max_length=1024)
|
||||||
default_username = models.CharField(blank=True, default='', max_length=1024)
|
default_username = models.CharField(blank=True, default='', max_length=1024)
|
||||||
ssh_password = models.CharField(blank=True, default='', max_length=1024)
|
ssh_password = models.CharField(blank=True, default='', max_length=1024)
|
||||||
sudo_password = models.CharField(blank=True, default='', max_length=1024)
|
sudo_password = models.CharField(blank=True, default='', max_length=1024)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def can_user_read(cls, user, obj):
|
||||||
|
''' a user can be read if they are on the same team or can be administrated '''
|
||||||
|
if user.is_superuser:
|
||||||
|
return True
|
||||||
|
if user == obj.user:
|
||||||
|
return True
|
||||||
|
if Organizations.filter(admins__in = [ user ], users__in = [ obj.user ]).count():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
import lib.urls
|
||||||
|
return reverse(lib.urls.views_CredentialsDetail, args=(self.pk,))
|
||||||
|
|
||||||
class Team(CommonModel):
|
class Team(CommonModel):
|
||||||
'''
|
'''
|
||||||
@@ -571,7 +592,7 @@ class Team(CommonModel):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def can_user_delete(cls, user, obj):
|
def can_user_delete(cls, user, obj):
|
||||||
return cls.can_user_administrate(user, obj)
|
return cls.can_user_administrate(user, obj)
|
||||||
|
|
||||||
class Project(CommonModel):
|
class Project(CommonModel):
|
||||||
'''
|
'''
|
||||||
A project represents a playbook git repo that can access a set of inventories
|
A project represents a playbook git repo that can access a set of inventories
|
||||||
@@ -632,7 +653,7 @@ class Permission(CommonModelNameNotUnique):
|
|||||||
# for example, user A on inventory X has write permissions (PERM_INVENTORY_WRITE)
|
# for example, user A on inventory X has write permissions (PERM_INVENTORY_WRITE)
|
||||||
# team C on inventory X has read permissions (PERM_INVENTORY_READ)
|
# team C on inventory X has read permissions (PERM_INVENTORY_READ)
|
||||||
# team C on inventory X and project Y has launch permissions (PERM_INVENTORY_DEPLOY)
|
# team C on inventory X and project Y has launch permissions (PERM_INVENTORY_DEPLOY)
|
||||||
# team C on inventory X and project Z has dry run permissions (PERM_INVENTORY_CHECK)
|
# team C on inventory X and project Z has dry run permissions (PERM_INVENTORY_CHECK)
|
||||||
#
|
#
|
||||||
# basically for launching, permissions can be awarded to the whole inventory source or just the inventory source
|
# basically for launching, permissions can be awarded to the whole inventory source or just the inventory source
|
||||||
# in context of a given project.
|
# in context of a given project.
|
||||||
@@ -640,14 +661,14 @@ class Permission(CommonModelNameNotUnique):
|
|||||||
# the project parameter is not used when dealing with READ, WRITE, or ADMIN permissions.
|
# the project parameter is not used when dealing with READ, WRITE, or ADMIN permissions.
|
||||||
|
|
||||||
permission_type = models.CharField(max_length=64, choices=PERMISSION_TYPE_CHOICES)
|
permission_type = models.CharField(max_length=64, choices=PERMISSION_TYPE_CHOICES)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode("Permission(name=%s,ON(user=%s,team=%s),FOR(project=%s,inventory=%s,type=%s))" % (
|
return unicode("Permission(name=%s,ON(user=%s,team=%s),FOR(project=%s,inventory=%s,type=%s))" % (
|
||||||
self.name,
|
self.name,
|
||||||
self.user,
|
self.user,
|
||||||
self.team,
|
self.team,
|
||||||
self.project,
|
self.project,
|
||||||
self.inventory,
|
self.inventory,
|
||||||
self.permission_type
|
self.permission_type
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
model = Credential
|
model = Credential
|
||||||
fields = (
|
fields = (
|
||||||
'url', 'id', 'related', 'name', 'description', 'creation_date',
|
'url', 'id', 'related', 'name', 'description', 'creation_date',
|
||||||
'ssh_key_path', 'ssh_key_data', 'ssh_key_unlock', 'ssh_password', 'sudo_password',
|
'default_username', 'ssh_key_data', 'ssh_key_unlock', 'ssh_password', 'sudo_password',
|
||||||
'user', 'team'
|
'user', 'team'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ class ProjectsTest(BaseTest):
|
|||||||
new_credentials = dict(
|
new_credentials = dict(
|
||||||
name = 'credential',
|
name = 'credential',
|
||||||
project = Project.objects.all()[0].pk,
|
project = Project.objects.all()[0].pk,
|
||||||
ssh_key_path = 'foo',
|
default_username = 'foo',
|
||||||
ssh_key_data = 'bar',
|
ssh_key_data = 'bar',
|
||||||
ssh_key_unlock = 'baz',
|
ssh_key_unlock = 'baz',
|
||||||
ssh_password = 'narf',
|
ssh_password = 'narf',
|
||||||
|
|||||||
@@ -88,8 +88,12 @@ class RunLaunchJobTest(BaseCeleryTest):
|
|||||||
launch_job_status = self.launch_job.start()
|
launch_job_status = self.launch_job.start()
|
||||||
self.assertEqual(launch_job_status.status, 'pending')
|
self.assertEqual(launch_job_status.status, 'pending')
|
||||||
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
launch_job_status = LaunchJobStatus.objects.get(pk=launch_job_status.pk)
|
||||||
#print 'stdout:', launch_job_status.result_stdout
|
print 'stdout:', launch_job_status.result_stdout
|
||||||
#print 'stderr:', launch_job_status.result_stderr
|
print 'stderr:', launch_job_status.result_stderr
|
||||||
|
print launch_job_status.status
|
||||||
|
|
||||||
|
print settings.DATABASES
|
||||||
|
|
||||||
self.assertEqual(launch_job_status.status, 'successful')
|
self.assertEqual(launch_job_status.status, 'successful')
|
||||||
self.assertTrue(launch_job_status.result_stdout)
|
self.assertTrue(launch_job_status.result_stdout)
|
||||||
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
launch_job_status_events = launch_job_status.launch_job_status_events.all()
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ class OrganizationsList(BaseList):
|
|||||||
|
|
||||||
# I can see the organizations if:
|
# I can see the organizations if:
|
||||||
# I am a superuser
|
# I am a superuser
|
||||||
# I am an admin of the organization
|
# I am an admin of the organization
|
||||||
# I am a member of the organization
|
# I am a member of the organization
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
||||||
base = Organization.objects
|
base = Organization.objects
|
||||||
@@ -78,7 +78,7 @@ class OrganizationsAuditTrailList(BaseSubList):
|
|||||||
|
|
||||||
|
|
||||||
class OrganizationsUsersList(BaseSubList):
|
class OrganizationsUsersList(BaseSubList):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -95,7 +95,7 @@ class OrganizationsUsersList(BaseSubList):
|
|||||||
return User.objects.filter(organizations__in = [ organization ])
|
return User.objects.filter(organizations__in = [ organization ])
|
||||||
|
|
||||||
class OrganizationsAdminsList(BaseSubList):
|
class OrganizationsAdminsList(BaseSubList):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -112,7 +112,7 @@ class OrganizationsAdminsList(BaseSubList):
|
|||||||
return User.objects.filter(admin_of_organizations__in = [ organization ])
|
return User.objects.filter(admin_of_organizations__in = [ organization ])
|
||||||
|
|
||||||
class OrganizationsProjectsList(BaseSubList):
|
class OrganizationsProjectsList(BaseSubList):
|
||||||
|
|
||||||
model = Project
|
model = Project
|
||||||
serializer_class = ProjectSerializer
|
serializer_class = ProjectSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -120,7 +120,7 @@ class OrganizationsProjectsList(BaseSubList):
|
|||||||
relationship = 'projects' # " "
|
relationship = 'projects' # " "
|
||||||
postable = True
|
postable = True
|
||||||
inject_primary_key_on_post_as = 'organization'
|
inject_primary_key_on_post_as = 'organization'
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
''' to list projects in the organization, I must be a superuser or org admin '''
|
''' to list projects in the organization, I must be a superuser or org admin '''
|
||||||
organization = Organization.objects.get(pk=self.kwargs['pk'])
|
organization = Organization.objects.get(pk=self.kwargs['pk'])
|
||||||
@@ -129,7 +129,7 @@ class OrganizationsProjectsList(BaseSubList):
|
|||||||
return Project.objects.filter(organizations__in = [ organization ])
|
return Project.objects.filter(organizations__in = [ organization ])
|
||||||
|
|
||||||
class OrganizationsTagsList(BaseSubList):
|
class OrganizationsTagsList(BaseSubList):
|
||||||
|
|
||||||
model = Tag
|
model = Tag
|
||||||
serializer_class = TagSerializer
|
serializer_class = TagSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -147,7 +147,7 @@ class OrganizationsTagsList(BaseSubList):
|
|||||||
return Tag.objects.filter(organization_by_tag__in = [ organization ])
|
return Tag.objects.filter(organization_by_tag__in = [ organization ])
|
||||||
|
|
||||||
class OrganizationsTeamsList(BaseSubList):
|
class OrganizationsTeamsList(BaseSubList):
|
||||||
|
|
||||||
model = Team
|
model = Team
|
||||||
serializer_class = TeamSerializer
|
serializer_class = TeamSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -174,7 +174,7 @@ class TeamsList(BaseList):
|
|||||||
# I am a superuser
|
# I am a superuser
|
||||||
# I am an admin of the organization that the team is
|
# I am an admin of the organization that the team is
|
||||||
# I am on that team
|
# I am on that team
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
||||||
base = Team.objects
|
base = Team.objects
|
||||||
@@ -193,7 +193,7 @@ class TeamsDetail(BaseDetail):
|
|||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
class TeamsUsersList(BaseSubList):
|
class TeamsUsersList(BaseSubList):
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
@@ -224,7 +224,7 @@ class ProjectsList(BaseList):
|
|||||||
# I am a superuser
|
# I am a superuser
|
||||||
# I am an admin of the organization that contains the project
|
# I am an admin of the organization that contains the project
|
||||||
# I am a member of a team that also contains the project
|
# I am a member of a team that also contains the project
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
''' I can see organizations when I am a superuser, or I am an admin or user in that organization '''
|
||||||
base = Project.objects
|
base = Project.objects
|
||||||
@@ -279,15 +279,15 @@ class UsersList(BaseList):
|
|||||||
user = User.objects.get(pk=pk)
|
user = User.objects.get(pk=pk)
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.save()
|
user.save()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
''' I can see user records when I'm a superuser, I'm that user, I'm their org admin, or I'm on a team with that user '''
|
''' I can see user records when I'm a superuser, I'm that user, I'm their org admin, or I'm on a team with that user '''
|
||||||
base = User.objects
|
base = User.objects
|
||||||
if self.request.user.is_superuser:
|
if self.request.user.is_superuser:
|
||||||
return base.all()
|
return base.all()
|
||||||
mine = base.filter(pk = self.request.user.pk).distinct()
|
mine = base.filter(pk = self.request.user.pk).distinct()
|
||||||
admin_of = base.filter(organizations__in = self.request.user.admin_of_organizations.all()).distinct()
|
admin_of = base.filter(organizations__in = self.request.user.admin_of_organizations.all()).distinct()
|
||||||
same_team = base.filter(teams__in = self.request.user.teams.all()).distinct()
|
same_team = base.filter(teams__in = self.request.user.teams.all()).distinct()
|
||||||
return mine | admin_of | same_team
|
return mine | admin_of | same_team
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ class UsersOrganizationsList(BaseSubList):
|
|||||||
parent_model = User
|
parent_model = User
|
||||||
relationship = 'organizations'
|
relationship = 'organizations'
|
||||||
postable = False
|
postable = False
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
user = User.objects.get(pk=self.kwargs['pk'])
|
user = User.objects.get(pk=self.kwargs['pk'])
|
||||||
if not UserHelper.can_user_administrate(self.request.user, user):
|
if not UserHelper.can_user_administrate(self.request.user, user):
|
||||||
@@ -391,7 +391,7 @@ class UsersDetail(BaseDetail):
|
|||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
def put_filter(self, request, *args, **kwargs):
|
def put_filter(self, request, *args, **kwargs):
|
||||||
''' make sure non-read-only fields that can only be edited by admins, are only edited by admins '''
|
''' make sure non-read-only fields that can only be edited by admins, are only edited by admins '''
|
||||||
obj = User.objects.get(pk=kwargs['pk'])
|
obj = User.objects.get(pk=kwargs['pk'])
|
||||||
if EditHelper.illegal_changes(request, obj, UserHelper):
|
if EditHelper.illegal_changes(request, obj, UserHelper):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
@@ -400,6 +400,13 @@ class UsersDetail(BaseDetail):
|
|||||||
obj.save()
|
obj.save()
|
||||||
request.DATA.pop('password')
|
request.DATA.pop('password')
|
||||||
|
|
||||||
|
class CredentialsDetail(BaseDetail):
|
||||||
|
|
||||||
|
model = Credential
|
||||||
|
serializer_class = CredentialSerializer
|
||||||
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
|
|
||||||
class InventoryList(BaseList):
|
class InventoryList(BaseList):
|
||||||
|
|
||||||
model = Inventory
|
model = Inventory
|
||||||
@@ -438,9 +445,9 @@ class HostsList(BaseList):
|
|||||||
permission_classes = (CustomRbac,)
|
permission_classes = (CustomRbac,)
|
||||||
|
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
'''
|
'''
|
||||||
I can see hosts when:
|
I can see hosts when:
|
||||||
I'm a superuser,
|
I'm a superuser,
|
||||||
or an organization admin of an inventory they are in
|
or an organization admin of an inventory they are in
|
||||||
or when I have allowing read permissions via a user or team on an inventory they are in
|
or when I have allowing read permissions via a user or team on an inventory they are in
|
||||||
'''
|
'''
|
||||||
@@ -524,7 +531,7 @@ class GroupsChildrenList(BaseSubList):
|
|||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
|
|
||||||
# FIXME: this is the mostly the same as GroupsList, share code similar to how done with Host and Group objects.
|
# FIXME: this is the mostly the same as GroupsList, share code similar to how done with Host and Group objects.
|
||||||
|
|
||||||
parent = Group.objects.get(pk=self.kwargs['pk'])
|
parent = Group.objects.get(pk=self.kwargs['pk'])
|
||||||
|
|
||||||
# FIXME: verify read permissions on this object are still required at a higher level
|
# FIXME: verify read permissions on this object are still required at a higher level
|
||||||
|
|||||||
11
lib/urls.py
11
lib/urls.py
@@ -80,6 +80,9 @@ views_VariableDetail = views.VariableDetail.as_view()
|
|||||||
# tags service
|
# tags service
|
||||||
views_TagsDetail = views.TagsDetail.as_view()
|
views_TagsDetail = views.TagsDetail.as_view()
|
||||||
|
|
||||||
|
# credentials service
|
||||||
|
views_CredentialsDetail = views.CredentialsDetail.as_view()
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ urlpatterns = patterns('',
|
|||||||
url(r'^api/v1/projects/$', views_ProjectsList),
|
url(r'^api/v1/projects/$', views_ProjectsList),
|
||||||
url(r'^api/v1/projects/(?P<pk>[0-9]+)/$', views_ProjectsDetail),
|
url(r'^api/v1/projects/(?P<pk>[0-9]+)/$', views_ProjectsDetail),
|
||||||
url(r'^api/v1/projects/(?P<pk>[0-9]+)/organizations/$', views_ProjectsOrganizationsList),
|
url(r'^api/v1/projects/(?P<pk>[0-9]+)/organizations/$', views_ProjectsOrganizationsList),
|
||||||
|
|
||||||
# audit trail service
|
# audit trail service
|
||||||
# api/v1/audit_trails/
|
# api/v1/audit_trails/
|
||||||
# api/v1/audit_trails/N/
|
# api/v1/audit_trails/N/
|
||||||
@@ -119,7 +122,7 @@ urlpatterns = patterns('',
|
|||||||
url(r'^api/v1/teams/(?P<pk>[0-9]+)/$', views_TeamsDetail),
|
url(r'^api/v1/teams/(?P<pk>[0-9]+)/$', views_TeamsDetail),
|
||||||
url(r'^api/v1/teams/(?P<pk>[0-9]+)/users/$', views_TeamsUsersList),
|
url(r'^api/v1/teams/(?P<pk>[0-9]+)/users/$', views_TeamsUsersList),
|
||||||
|
|
||||||
# api/v1/teams/N/
|
# api/v1/teams/N/
|
||||||
# api/v1/teams/N/users/
|
# api/v1/teams/N/users/
|
||||||
|
|
||||||
# inventory service
|
# inventory service
|
||||||
@@ -155,9 +158,7 @@ urlpatterns = patterns('',
|
|||||||
# ... and tag relations on all resources
|
# ... and tag relations on all resources
|
||||||
|
|
||||||
# credentials services
|
# credentials services
|
||||||
# ... users
|
url(r'^api/v1/credentials/(?P<pk>[0-9]+)/$', views_CredentialsDetail),
|
||||||
# ... teams
|
|
||||||
# ... projects (?)
|
|
||||||
|
|
||||||
# permissions services
|
# permissions services
|
||||||
# ... users
|
# ... users
|
||||||
|
|||||||
Reference in New Issue
Block a user