Skip to content

Commit 37ce448

Browse files
author
Gabriel Monroy
committed
first pass at formation permissions
1 parent e3d3ed2 commit 37ce448

3 files changed

Lines changed: 38 additions & 17 deletions

File tree

api/fixtures/tests.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"first_name": "Otto",
88
"last_name": "Test",
99
"is_active": true,
10-
"is_superuser": false,
10+
"is_superuser": true,
1111
"is_staff": true,
1212
"last_login": "2013-05-10T16:08:09.357Z",
1313
"groups": [],

api/serializers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class AdminUserSerializer(serializers.ModelSerializer):
5050
class Meta:
5151
model = User
5252
fields = ('username', 'is_superuser')
53-
read_only_fields = ('username', )
53+
read_only_fields = ('username',)
5454

5555

5656
class KeySerializer(serializers.ModelSerializer):
@@ -169,7 +169,7 @@ class AppSerializer(serializers.ModelSerializer):
169169

170170
owner = serializers.Field(source='owner.username')
171171
id = serializers.SlugField(default=utils.generate_app_name)
172-
formation = OwnerSlugRelatedField(slug_field='id', required=False)
172+
formation = serializers.SlugRelatedField(slug_field='id', required=False)
173173

174174
class Meta:
175175
"""Metadata options for a :class:`AppSerializer`."""

api/views.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ def has_permission(self, request, view):
9494
return request.user.is_superuser
9595

9696

97+
class IsAdminOrSafeMethod(permissions.BasePermission):
98+
"""
99+
View permission to allow only admins to use unsafe methods
100+
including POST, PUT, DELETE.
101+
102+
This allows
103+
"""
104+
105+
def has_permission(self, request, view):
106+
"""
107+
Return `True` if permission is granted, `False` otherwise.
108+
"""
109+
return request.method in permissions.SAFE_METHODS or request.user.is_superuser
110+
111+
97112
class UserRegistrationView(viewsets.GenericViewSet,
98113
viewsets.mixins.CreateModelMixin):
99114
model = User
@@ -187,13 +202,18 @@ def update(self, request, *args, **kwargs):
187202
return super(FlavorViewSet, self).update(request, *args, **kwargs)
188203

189204

190-
class FormationViewSet(OwnerViewSet):
205+
class FormationViewSet(viewsets.ModelViewSet):
191206
"""RESTful views for :class:`~api.models.Formation`."""
192207

193208
model = models.Formation
194209
serializer_class = serializers.FormationSerializer
210+
permission_classes = (permissions.IsAuthenticated, IsAdminOrSafeMethod)
195211
lookup_field = 'id'
196212

213+
def pre_save(self, obj):
214+
if not hasattr(obj, 'owner'):
215+
obj.owner = self.request.user
216+
197217
def post_save(self, formation, created=False, **kwargs):
198218
if created:
199219
formation.build()
@@ -246,14 +266,18 @@ def destroy(self, request, **kwargs):
246266
return Response(status=status.HTTP_204_NO_CONTENT)
247267

248268

249-
class FormationScopedViewSet(OwnerViewSet):
269+
class FormationScopedViewSet(viewsets.ModelViewSet):
270+
271+
permission_classes = (permissions.IsAuthenticated, IsAdmin)
272+
273+
def pre_save(self, obj):
274+
if not hasattr(obj, 'owner'):
275+
obj.owner = self.request.user
250276

251277
def get_queryset(self, **kwargs):
252-
formations = models.Formation.objects.filter(
253-
owner=self.request.user)
278+
formations = models.Formation.objects.all()
254279
formation = get_object_or_404(formations, id=self.kwargs['id'])
255-
return self.model.objects.filter(owner=self.request.user,
256-
formation=formation)
280+
return self.model.objects.filter(formation=formation)
257281

258282

259283
class FormationLayerViewSet(FormationScopedViewSet):
@@ -269,15 +293,14 @@ def get_object(self, *args, **kwargs):
269293

270294
def create(self, request, **kwargs):
271295
request._data = request.DATA.copy()
272-
formation = models.Formation.objects.get(
273-
owner=self.request.user, id=self.kwargs['id'])
296+
formation = models.Formation.objects.get(id=self.kwargs['id'])
274297
request.DATA['formation'] = formation.id
275298
if not 'ssh_private_key' in request.DATA and not 'ssh_public_key' in request.DATA:
276299
# SECURITY: figure out best way to get keys with proper entropy
277300
key = RSA.generate(2048)
278301
request.DATA['ssh_private_key'] = key.exportKey('PEM')
279302
request.DATA['ssh_public_key'] = key.exportKey('OpenSSH')
280-
return OwnerViewSet.create(self, request, **kwargs)
303+
return super(FormationLayerViewSet, self).create(request, **kwargs)
281304

282305
def post_save(self, layer, created=False, **kwargs):
283306
if created:
@@ -302,10 +325,8 @@ def get_object(self, *args, **kwargs):
302325

303326
def add(self, request, **kwargs):
304327
fqdn = request.DATA['fqdn']
305-
formation = models.Formation.objects.get(
306-
owner=self.request.user, id=self.kwargs['id'])
307-
layer = models.Layer.objects.get(
308-
owner=self.request.user, id=request.DATA['layer'])
328+
formation = models.Formation.objects.get(id=self.kwargs['id'])
329+
layer = models.Layer.objects.get(id=request.DATA['layer'])
309330
if self.model.objects.filter(fqdn=fqdn, formation=formation, layer=layer).exists():
310331
msg = "A node with fqdn={} already exists in the {} formation".format(fqdn, formation)
311332
return Response(data=msg, status=status.HTTP_409_CONFLICT)
@@ -394,7 +415,7 @@ class NodeViewSet(FormationNodeViewSet):
394415
"""RESTful views for :class:`~api.models.Node`."""
395416

396417
def get_queryset(self, **kwargs):
397-
return self.model.objects.filter(owner=self.request.user)
418+
return self.model.objects.all()
398419

399420
def converge(self, request, **kwargs):
400421
node = self.get_object()

0 commit comments

Comments
 (0)