Skip to content

Commit ae10569

Browse files
author
Matthew Fisher
committed
ref(controller): use permission_classes decorator
AppPermsViewSet is a special snowflake which requires different permissions for different views, so we can circumvent this by using a permission_classes decorator instead of injecting the permissions directly.
1 parent cb4ae03 commit ae10569

3 files changed

Lines changed: 25 additions & 13 deletions

File tree

controller/api/permissions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ def has_object_permission(self, request, view, obj):
4242
return False
4343

4444

45+
class IsOwnerOrAdmin(permissions.BasePermission):
46+
"""
47+
Object-level permission to allow only owners of an object or administrators to access it.
48+
Assumes the model instance has an `owner` attribute.
49+
"""
50+
def has_object_permission(self, request, view, obj):
51+
if request.user.is_superuser:
52+
return True
53+
if hasattr(obj, 'owner'):
54+
return obj.owner == request.user
55+
else:
56+
return False
57+
58+
4559
class IsAppUser(permissions.BasePermission):
4660
"""
4761
Object-level permission to allow owners or collaborators to access

controller/api/tests/test_perm.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ def test_delete(self):
215215
response = self.client.delete(url, content_type='application/json',
216216
HTTP_AUTHORIZATION='token {}'.format(self.token2))
217217
self.assertEqual(response.status_code, 403)
218-
self.assertIsNone(response.data)
219218
# delete permission to user 1's app
220219
response = self.client.delete(url, content_type='application/json',
221220
HTTP_AUTHORIZATION='token {}'.format(self.token))

controller/api/views.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from guardian.shortcuts import assign_perm, get_objects_for_user, \
1010
get_users_with_perms, remove_perm
1111
from rest_framework import mixins, renderers, status
12+
from rest_framework.decorators import permission_classes
1213
from rest_framework.exceptions import PermissionDenied
1314
from rest_framework.permissions import IsAuthenticated
1415
from rest_framework.response import Response
@@ -319,33 +320,31 @@ class AppPermsViewSet(BaseDeisViewSet):
319320
model = models.App # models class
320321
perm = 'use_app' # short name for permission
321322

323+
def get_queryset(self):
324+
return self.model.objects.all()
325+
326+
@permission_classes([permissions.IsAppUser])
322327
def list(self, request, **kwargs):
323-
app = get_object_or_404(self.model, id=kwargs['id'])
328+
app = self.get_object()
324329
perm_name = "api.{}".format(self.perm)
325-
if request.user != app.owner and \
326-
not request.user.has_perm(perm_name, app) and \
327-
not request.user.is_superuser:
328-
return Response(status=status.HTTP_403_FORBIDDEN)
329330
usernames = [u.username for u in get_users_with_perms(app)
330331
if u.has_perm(perm_name, app)]
331332
return Response({'users': usernames})
332333

334+
@permission_classes([permissions.IsOwnerOrAdmin])
333335
def create(self, request, **kwargs):
334-
app = get_object_or_404(self.model, id=kwargs['id'])
335-
if request.user != app.owner and not request.user.is_superuser:
336-
return Response(status=status.HTTP_403_FORBIDDEN)
336+
app = self.get_object()
337337
user = get_object_or_404(User, username=request.data['username'])
338338
assign_perm(self.perm, user, app)
339339
models.log_event(app, "User {} was granted access to {}".format(user, app))
340340
return Response(status=status.HTTP_201_CREATED)
341341

342+
@permission_classes([permissions.IsOwnerOrAdmin])
342343
def destroy(self, request, **kwargs):
343-
app = get_object_or_404(self.model, id=kwargs['id'])
344-
if request.user != app.owner and not request.user.is_superuser:
345-
return Response(status=status.HTTP_403_FORBIDDEN)
344+
app = self.get_object()
346345
user = get_object_or_404(User, username=kwargs['username'])
347346
if not user.has_perm(self.perm, app):
348-
return Response(status=status.HTTP_403_FORBIDDEN)
347+
raise PermissionDenied()
349348
remove_perm(self.perm, user, app)
350349
models.log_event(app, "User {} was revoked access to {}".format(user, app))
351350
return Response(status=status.HTTP_204_NO_CONTENT)

0 commit comments

Comments
 (0)