|
@@ -4,13 +4,11 @@ from Crypto.PublicKey import RSA
|
|
from django.core.urlresolvers import reverse
|
|
from django.core.urlresolvers import reverse
|
|
from django.http import HttpResponseBadRequest
|
|
from django.http import HttpResponseBadRequest
|
|
|
|
|
|
-from rest_framework.authentication import BasicAuthentication, SessionAuthentication
|
|
|
|
|
|
+from rest_framework.exceptions import ValidationError
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.permissions import IsAuthenticated
|
|
-from rest_framework.renderers import JSONRenderer
|
|
|
|
from rest_framework.response import Response
|
|
from rest_framework.response import Response
|
|
-from rest_framework.viewsets import GenericViewSet, ModelViewSet, ViewSet
|
|
|
|
|
|
+from rest_framework.viewsets import ModelViewSet, ViewSet
|
|
|
|
|
|
-from extras.api.renderers import FormlessBrowsableAPIRenderer, FreeRADIUSClientsRenderer
|
|
|
|
from secrets.exceptions import InvalidSessionKey
|
|
from secrets.exceptions import InvalidSessionKey
|
|
from secrets.filters import SecretFilter
|
|
from secrets.filters import SecretFilter
|
|
from secrets.models import Secret, SecretRole, SessionKey, UserKey
|
|
from secrets.models import Secret, SecretRole, SessionKey, UserKey
|
|
@@ -38,7 +36,6 @@ class SecretRoleViewSet(ModelViewSet):
|
|
# Secrets
|
|
# Secrets
|
|
#
|
|
#
|
|
|
|
|
|
-# TODO: Need to implement custom create() and update() methods to handle secret encryption.
|
|
|
|
class SecretViewSet(WritableSerializerMixin, ModelViewSet):
|
|
class SecretViewSet(WritableSerializerMixin, ModelViewSet):
|
|
queryset = Secret.objects.select_related(
|
|
queryset = Secret.objects.select_related(
|
|
'device__primary_ip4', 'device__primary_ip6', 'role',
|
|
'device__primary_ip4', 'device__primary_ip6', 'role',
|
|
@@ -48,11 +45,21 @@ class SecretViewSet(WritableSerializerMixin, ModelViewSet):
|
|
serializer_class = serializers.SecretSerializer
|
|
serializer_class = serializers.SecretSerializer
|
|
write_serializer_class = serializers.WritableSecretSerializer
|
|
write_serializer_class = serializers.WritableSecretSerializer
|
|
filter_class = SecretFilter
|
|
filter_class = SecretFilter
|
|
- # DRF's BrowsableAPIRenderer can't support passing the secret key as a header, so we disable it.
|
|
|
|
- renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
|
|
|
|
|
|
|
|
master_key = None
|
|
master_key = None
|
|
|
|
|
|
|
|
+ def _get_encrypted_fields(self, serializer):
|
|
|
|
+ """
|
|
|
|
+ Since we can't call encrypt() on the serializer like we can on the Secret model, we need to calculate the
|
|
|
|
+ ciphertext and hash values by encrypting a dummy copy. These can be passed to the serializer's save() method.
|
|
|
|
+ """
|
|
|
|
+ s = Secret(plaintext=serializer.validated_data['plaintext'])
|
|
|
|
+ s.encrypt(self.master_key)
|
|
|
|
+ return ({
|
|
|
|
+ 'ciphertext': s.ciphertext,
|
|
|
|
+ 'hash': s.hash,
|
|
|
|
+ })
|
|
|
|
+
|
|
def initial(self, request, *args, **kwargs):
|
|
def initial(self, request, *args, **kwargs):
|
|
|
|
|
|
super(SecretViewSet, self).initial(request, *args, **kwargs)
|
|
super(SecretViewSet, self).initial(request, *args, **kwargs)
|
|
@@ -66,13 +73,18 @@ class SecretViewSet(WritableSerializerMixin, ModelViewSet):
|
|
else:
|
|
else:
|
|
session_key = None
|
|
session_key = None
|
|
|
|
|
|
|
|
+ # We can't encrypt secret plaintext without a session key.
|
|
|
|
+ # assert False, self.action
|
|
|
|
+ if self.action in ['create', 'update'] and session_key is None:
|
|
|
|
+ raise ValidationError("A session key must be provided when creating or updating secrets.")
|
|
|
|
+
|
|
# Attempt to retrieve the master key for encryption/decryption if a session key has been provided.
|
|
# Attempt to retrieve the master key for encryption/decryption if a session key has been provided.
|
|
if session_key is not None:
|
|
if session_key is not None:
|
|
try:
|
|
try:
|
|
sk = SessionKey.objects.get(userkey__user=request.user)
|
|
sk = SessionKey.objects.get(userkey__user=request.user)
|
|
self.master_key = sk.get_master_key(session_key)
|
|
self.master_key = sk.get_master_key(session_key)
|
|
except (SessionKey.DoesNotExist, InvalidSessionKey):
|
|
except (SessionKey.DoesNotExist, InvalidSessionKey):
|
|
- return HttpResponseBadRequest("Invalid session key.")
|
|
|
|
|
|
+ raise ValidationError("Invalid session key.")
|
|
|
|
|
|
def retrieve(self, request, *args, **kwargs):
|
|
def retrieve(self, request, *args, **kwargs):
|
|
|
|
|
|
@@ -107,6 +119,12 @@ class SecretViewSet(WritableSerializerMixin, ModelViewSet):
|
|
serializer = self.get_serializer(queryset, many=True)
|
|
serializer = self.get_serializer(queryset, many=True)
|
|
return Response(serializer.data)
|
|
return Response(serializer.data)
|
|
|
|
|
|
|
|
+ def perform_create(self, serializer):
|
|
|
|
+ serializer.save(**self._get_encrypted_fields(serializer))
|
|
|
|
+
|
|
|
|
+ def perform_update(self, serializer):
|
|
|
|
+ serializer.save(**self._get_encrypted_fields(serializer))
|
|
|
|
+
|
|
|
|
|
|
class GetSessionKeyViewSet(ViewSet):
|
|
class GetSessionKeyViewSet(ViewSet):
|
|
"""
|
|
"""
|