Superuser fix redux.

This commit is contained in:
Luke Sneeringer
2014-11-10 08:43:16 -06:00
parent db6a068c4a
commit 71946d3802

View File

@@ -5,6 +5,7 @@
# Python # Python
import datetime import datetime
import dateutil import dateutil
import functools
import time import time
import re import re
import socket import socket
@@ -431,30 +432,32 @@ class DashboardInventoryGraphView(APIView):
return Response(dashboard_data) return Response(dashboard_data)
class UserCreateAPIMixin(object): def disallow_superuser_escalation(cls):
"""A mixin subclass that ensures that only a superuser is able to create """Decorator that ensures that the post, put, and patch methods on the
another superuser. class, if they exist, perform a sanity check and disallow superuser
escalation by non-superusers.
""" """
def post(self, request, pk=None): # Create a method decorator that ensures superuser escalation by
self._superuser_sanity_check(request) # non-superusers is disallowed.
return super(UserCreateAPIMixin, self).post(request, pk=pk) def superuser_lockdown(method):
@functools.wraps(method)
def fx(self, request, *a, **kw):
if not request.user.is_superuser:
if request.DATA.get('is_superuser', False):
raise PermissionDenied('Only superusers may create '
'other superusers.')
return method(self, request, *a, **kw)
return fx
# def put(self, request, pk=None): # Ensure that if post, put, or patch methods exist, that they are decorated
# self._superuser_sanity_check(request) # with the sanity check decorator.
# return super(UserCreateAPIMixin, self).put(request, pk=pk) for vuln_method in ('post', 'put', 'patch'):
original_method = getattr(cls, vuln_method, None)
if original_method is not None:
setattr(cls, vuln_method, superuser_lockdown(original_method))
# def patch(self, request, pk=None): # Return the class object.
# self._superuser_sanity_check(request) return cls
# return super(UserCreateAPIMixin, self).patch(request, pk=pk)
def _superuser_sanity_check(self, request):
"""Ensure that if a non-superuser tries to create a superuser,
that the request is rejected.
"""
if not request.user.is_superuser:
if request.DATA.get('is_superuser', False):
raise PermissionDenied('Only superusers may create '
'other superusers.')
class ScheduleList(ListAPIView): class ScheduleList(ListAPIView):
@@ -518,14 +521,16 @@ class OrganizationInventoriesList(SubListAPIView):
parent_model = Organization parent_model = Organization
relationship = 'inventories' relationship = 'inventories'
class OrganizationUsersList(UserCreateAPIMixin, SubListCreateAPIView): @disallow_superuser_escalation
class OrganizationUsersList(SubListCreateAPIView):
model = User model = User
serializer_class = UserSerializer serializer_class = UserSerializer
parent_model = Organization parent_model = Organization
relationship = 'users' relationship = 'users'
class OrganizationAdminsList(UserCreateAPIMixin, SubListCreateAPIView): @disallow_superuser_escalation
class OrganizationAdminsList(SubListCreateAPIView):
model = User model = User
serializer_class = UserSerializer serializer_class = UserSerializer
@@ -565,7 +570,8 @@ class TeamDetail(RetrieveUpdateDestroyAPIView):
model = Team model = Team
serializer_class = TeamSerializer serializer_class = TeamSerializer
class TeamUsersList(UserCreateAPIMixin, SubListCreateAPIView): @disallow_superuser_escalation
class TeamUsersList(SubListCreateAPIView):
model = User model = User
serializer_class = UserSerializer serializer_class = UserSerializer
@@ -760,7 +766,9 @@ class ProjectUpdateCancel(GenericAPIView):
else: else:
return self.http_method_not_allowed(request, *args, **kwargs) return self.http_method_not_allowed(request, *args, **kwargs)
class UserList(UserCreateAPIMixin, ListCreateAPIView):
@disallow_superuser_escalation
class UserList(ListCreateAPIView):
model = User model = User
serializer_class = UserSerializer serializer_class = UserSerializer