1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 23:51:09 +03:00

Added and updated several credential creation and listing API endpoints

Should addres #1379
This commit is contained in:
Akita Noek 2016-04-01 16:57:08 -04:00
parent 28acc9516d
commit 23aca083eb
6 changed files with 116 additions and 58 deletions

View File

@ -1505,7 +1505,7 @@ class CredentialSerializer(BaseSerializer):
class Meta:
model = Credential
fields = ('*', 'deprecated_user', 'deprecated_team', 'kind', 'cloud', 'host', 'username',
fields = ('*', 'kind', 'cloud', 'host', 'username',
'password', 'security_token', 'project', 'domain',
'ssh_key_data', 'ssh_key_unlock',
'become_method', 'become_username', 'become_password',
@ -1519,21 +1519,6 @@ class CredentialSerializer(BaseSerializer):
field_kwargs['default'] = ''
return field_class, field_kwargs
def to_representation(self, obj):
ret = super(CredentialSerializer, self).to_representation(obj)
if obj is not None and 'deprecated_user' in ret and not obj.deprecated_user:
ret['deprecated_user'] = None
if obj is not None and 'deprecated_team' in ret and not obj.deprecated_team:
ret['deprecated_team'] = None
return ret
def validate(self, attrs):
# Ensure old style assignment for user/team is always None
attrs['deprecated_user'] = None
attrs['deprecated_team'] = None
return super(CredentialSerializer, self).validate(attrs)
def get_related(self, obj):
res = super(CredentialSerializer, self).get_related(obj)
res.update(dict(

View File

@ -19,6 +19,7 @@ organization_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/inventories/$', 'organization_inventories_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', 'organization_projects_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', 'organization_teams_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', 'organization_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'organization_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notifiers/$', 'organization_notifiers_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'organization_notifiers_any_list'),

View File

@ -824,21 +824,6 @@ class TeamProjectsList(SubListAPIView):
return team_qs & user_qs
class TeamCredentialsList(SubListAPIView):
model = Credential
serializer_class = CredentialSerializer
parent_model = Team
def get_queryset(self):
team = self.get_parent_object()
self.check_parent_access(team)
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
team_creds = Credential.objects.filter(owner_role__parents=team.member_role)
return team_creds & visible_creds
class TeamActivityStreamList(SubListAPIView):
model = ActivityStream
@ -1109,20 +1094,6 @@ class UserProjectsList(SubListAPIView):
user_qs = Project.accessible_objects(parent, {'read': True})
return my_qs & user_qs
class UserCredentialsList(SubListAPIView):
model = Credential
serializer_class = CredentialSerializer
parent_model = User
def get_queryset(self):
user = self.get_parent_object()
self.check_parent_access(user)
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
user_creds = Credential.accessible_objects(user, {'read': True})
return user_creds & visible_creds
class UserOrganizationsList(SubListAPIView):
model = Organization
@ -1216,6 +1187,104 @@ class CredentialList(ListCreateAPIView):
model = Credential
serializer_class = CredentialSerializer
def post(self, request, *args, **kwargs):
if not any([x in request.data for x in ['user', 'team', 'organization']]):
return Response({'detail': 'Missing user, team, or organization'}, status=status.HTTP_400_BAD_REQUEST)
if sum([1 if x in request.data else 0 for x in ['user', 'team', 'organization']]) != 1:
return Response({'detail': 'Expecting exactly one of user, team, or organization'}, status=status.HTTP_400_BAD_REQUEST)
if 'user' in request.data:
user = User.objects.get(pk=request.data['user'])
obj = user
if 'team' in request.data:
team = Team.objects.get(pk=request.data['team'])
obj = team
if 'organization' in request.data:
organization = Organization.objects.get(pk=request.data['organization'])
obj = organization
if not obj.accessible_by(self.request.user, {'write': True}):
raise PermissionDenied()
ret = super(CredentialList, self).post(request, *args, **kwargs)
credential = Credential.objects.get(id=ret.data['id'])
if 'user' in request.data:
credential.owner_role.members.add(user)
if 'team' in request.data:
credential.owner_role.parents.add(team.member_role)
if 'organization' in request.data:
credential.owner_role.parents.add(organization.admin_role)
return ret
class UserCredentialsList(CredentialList):
model = Credential
serializer_class = CredentialSerializer
def get_queryset(self):
user = User.objects.get(pk=self.kwargs['pk'])
if not self.request.user.can_access(User, 'read', user):
raise PermissionDenied()
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
user_creds = Credential.accessible_objects(user, {'read': True})
return user_creds & visible_creds
def post(self, request, *args, **kwargs):
user = User.objects.get(pk=self.kwargs['pk'])
request.data['user'] = user.id
# The following post takes care of ensuring the current user can add a cred to this user
return super(UserCredentialsList, self).post(request, args, kwargs)
class TeamCredentialsList(CredentialList):
model = Credential
serializer_class = CredentialSerializer
def get_queryset(self):
team = Team.objects.get(pk=self.kwargs['pk'])
if not self.request.user.can_access(Team, 'read', team):
raise PermissionDenied()
visible_creds = Credential.accessible_objects(self.request.user, {'read': True})
team_creds = Credential.objects.filter(owner_role__parents=team.member_role)
return team_creds & visible_creds
def post(self, request, *args, **kwargs):
team = Team.objects.get(pk=self.kwargs['pk'])
request.data['team'] = team.id
# The following post takes care of ensuring the current user can add a cred to this user
return super(TeamCredentialsList, self).post(request, args, kwargs)
class OrganizationCredentialList(CredentialList):
model = Credential
serializer_class = CredentialSerializer
def get_queryset(self):
organization = Organization.objects.get(pk=self.kwargs['pk'])
if not self.request.user.can_access(Organization, 'read', organization):
raise PermissionDenied()
user_visible = Credential.accessible_objects(self.request.user, {'read': True}).all()
org_set = Credential.accessible_objects(organization.admin_role, {'read': True}).all()
if self.request.user.is_superuser:
return org_set
return org_set & user_visible
def post(self, request, *args, **kwargs):
organization = Organization.objects.get(pk=self.kwargs['pk'])
request.data['organization'] = organization.id
# The following post takes care of ensuring the current user can add a cred to this user
return super(OrganizationCredentialList, self).post(request, args, kwargs)
class CredentialDetail(RetrieveUpdateDestroyAPIView):
model = Credential

View File

@ -542,20 +542,12 @@ class CredentialAccess(BaseAccess):
qs = self.model.accessible_objects(self.user, {'read':True})
return qs.select_related('created_by', 'modified_by').all()
def can_read(self, obj):
return obj.accessible_by(self.user, {'read': True})
def can_add(self, data):
if self.user.is_superuser:
return True
if 'user' in data:
pk = get_pk_from_dict(data, 'user')
user = get_object_or_400(User, pk=pk)
return user.accessible_by(self.user, {'write': True})
elif 'organization' in data:
pk = get_pk_from_dict(data, 'organization')
org = get_object_or_400(Organization, pk=pk)
return org.accessible_by(self.user, {'write': True})
return False
# Access enforced in our view where we have context enough to make a decision
return True
def can_change(self, obj, data):
if self.user.is_superuser:

View File

@ -43,6 +43,10 @@ class ResourceMixin(models.Model):
qs = cls.objects.filter(
role_permissions__role__ancestors__members=accessor
)
elif type(accessor) == Role:
qs = cls.objects.filter(
role_permissions__role__ancestors=accessor
)
else:
accessor_type = ContentType.objects.get_for_model(accessor)
roles = Role.objects.filter(content_type__pk=accessor_type.id,

View File

@ -92,6 +92,13 @@ def deploy_jobtemplate(project, inventory, credential):
def team(organization):
return organization.teams.create(name='test-team')
@pytest.fixture
def team_member(user, team):
ret = user('team-member', False)
team.member_role.members.add(ret)
return ret
@pytest.fixture
@mock.patch.object(Project, "update", lambda self, **kwargs: None)
def project(instance, organization):