Closes #985: Added preserve_key to get-session-key endpoint

This commit is contained in:
Jeremy Stretch 2017-03-28 11:13:13 -04:00
parent cf3e7f90d6
commit 5d022a575a
3 changed files with 39 additions and 14 deletions

View File

@ -1,7 +1,6 @@
import base64 import base64
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from django.core.urlresolvers import reverse
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
@ -9,7 +8,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ViewSet from rest_framework.viewsets import ModelViewSet, ViewSet
from secrets.exceptions import InvalidSessionKey from secrets.exceptions import InvalidKey
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
from utilities.api import WritableSerializerMixin from utilities.api import WritableSerializerMixin
@ -84,7 +83,7 @@ class SecretViewSet(WritableSerializerMixin, ModelViewSet):
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, InvalidKey):
raise ValidationError("Invalid session key.") raise ValidationError("Invalid session key.")
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
@ -140,6 +139,9 @@ class GetSessionKeyViewSet(ViewSet):
{ {
"session_key": "+8t4SI6XikgVmB5+/urhozx9O5qCQANyOk1MNe6taRf=" "session_key": "+8t4SI6XikgVmB5+/urhozx9O5qCQANyOk1MNe6taRf="
} }
This endpoint accepts one optional parameter: `preserve_key`. If True and a session key exists, the existing session
key will be returned instead of a new one.
""" """
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
@ -163,14 +165,26 @@ class GetSessionKeyViewSet(ViewSet):
if master_key is None: if master_key is None:
return HttpResponseBadRequest(ERR_PRIVKEY_INVALID) return HttpResponseBadRequest(ERR_PRIVKEY_INVALID)
# Delete the existing SessionKey for this user if one exists try:
SessionKey.objects.filter(userkey__user=request.user).delete() current_session_key = SessionKey.objects.get(userkey__user_id=request.user.pk)
except SessionKey.DoesNotExist:
current_session_key = None
# Create a new SessionKey if current_session_key and request.GET.get('preserve_key', False):
sk = SessionKey(userkey=user_key)
sk.save(master_key=master_key) # Retrieve the existing session key
encoded_key = base64.b64encode(sk.key) key = current_session_key.get_session_key(master_key)
# b64decode() returns a bytestring under Python 3
else:
# Create a new SessionKey
SessionKey.objects.filter(userkey__user=request.user).delete()
sk = SessionKey(userkey=user_key)
sk.save(master_key=master_key)
key = sk.key
# Encode the key using base64. (b64decode() returns a bytestring under Python 3.)
encoded_key = base64.b64encode(key)
if not isinstance(encoded_key, str): if not isinstance(encoded_key, str):
encoded_key = encoded_key.decode() encoded_key = encoded_key.decode()

View File

@ -1,5 +1,5 @@
class InvalidSessionKey(Exception): class InvalidKey(Exception):
""" """
Raised when the a provided session key is invalid. Raised when a provided key is invalid.
""" """
pass pass

View File

@ -13,7 +13,7 @@ from django.utils.encoding import force_bytes, python_2_unicode_compatible
from dcim.models import Device from dcim.models import Device
from utilities.models import CreatedUpdatedModel from utilities.models import CreatedUpdatedModel
from .exceptions import InvalidSessionKey from .exceptions import InvalidKey
from .hashers import SecretValidationHasher from .hashers import SecretValidationHasher
@ -221,13 +221,24 @@ class SessionKey(models.Model):
# Validate the provided session key # Validate the provided session key
if not check_password(session_key, self.hash): if not check_password(session_key, self.hash):
raise InvalidSessionKey() raise InvalidKey("Invalid session key")
# Decrypt master key using provided session key # Decrypt master key using provided session key
master_key = xor_keys(session_key, bytes(self.cipher)) master_key = xor_keys(session_key, bytes(self.cipher))
return master_key return master_key
def get_session_key(self, master_key):
# Recover session key using the master key
session_key = xor_keys(master_key, bytes(self.cipher))
# Validate the recovered session key
if not check_password(session_key, self.hash):
raise InvalidKey("Invalid master key")
return session_key
@python_2_unicode_compatible @python_2_unicode_compatible
class SecretRole(models.Model): class SecretRole(models.Model):