Authentication: move to msgpack for the encrypted parts.

master
Tom Hacohen 4 years ago
parent 85de674ee2
commit 453275eadf

@ -64,6 +64,15 @@ class BinaryBase64Field(serializers.Field):
return b64decode(data)
# This field does nothing to the data. It's useful for raw binary data
class RawField(serializers.Field):
def to_representation(self, value):
return value
def to_internal_value(self, data):
return data
class CollectionEncryptionKeyField(BinaryBase64Field):
def get_attribute(self, instance):
request = self.context.get('request', None)
@ -413,7 +422,7 @@ class AuthenticationLoginSerializer(serializers.Serializer):
class AuthenticationLoginInnerSerializer(AuthenticationLoginChallengeSerializer):
challenge = BinaryBase64Field()
challenge = RawField()
host = serializers.CharField()
action = serializers.CharField()

@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import msgpack
from functools import reduce
from django.conf import settings
@ -72,6 +72,14 @@ from .serializers import (
User = get_user_model()
def msgpack_encode(content):
return msgpack.packb(content, use_bin_type=True)
def msgpack_decode(content):
return msgpack.unpackb(content, raw=False)
class BaseViewSet(viewsets.ModelViewSet):
authentication_classes = tuple(app_settings.API_AUTHENTICATORS)
permission_classes = tuple(app_settings.API_PERMISSIONS)
@ -638,7 +646,7 @@ class AuthenticationViewSet(viewsets.ViewSet):
enc_key = self.get_encryption_key(salt)
box = nacl.secret.SecretBox(enc_key)
challenge_data = json.loads(box.decrypt(challenge).decode())
challenge_data = msgpack_decode(box.decrypt(challenge))
now = int(datetime.now().timestamp())
if action != expected_action:
content = {'code': 'wrong_action', 'detail': 'Expected "{}" but got something else'.format(expected_action)}
@ -680,8 +688,7 @@ class AuthenticationViewSet(viewsets.ViewSet):
"timestamp": int(datetime.now().timestamp()),
"userId": user.id,
}
challenge = box.encrypt(json.dumps(
challenge_data, separators=(',', ':')).encode(), encoder=nacl.encoding.RawEncoder)
challenge = box.encrypt(msgpack_encode(challenge_data), encoder=nacl.encoding.RawEncoder)
ret = {
"salt": b64encode(salt),
@ -698,10 +705,11 @@ class AuthenticationViewSet(viewsets.ViewSet):
outer_serializer.is_valid(raise_exception=True)
response_raw = outer_serializer.validated_data['response']
response = json.loads(response_raw.decode())
response = msgpack_decode(response_raw)
signature = outer_serializer.validated_data['signature']
serializer = AuthenticationLoginInnerSerializer(data=response, context={'host': request.get_host()})
context = {'host': request.get_host(), 'supports_binary': True}
serializer = AuthenticationLoginInnerSerializer(data=response, context=context)
serializer.is_valid(raise_exception=True)
bad_login_response = self.validate_login_request(
@ -730,11 +738,11 @@ class AuthenticationViewSet(viewsets.ViewSet):
outer_serializer.is_valid(raise_exception=True)
response_raw = outer_serializer.validated_data['response']
response = json.loads(response_raw.decode())
response = msgpack_decode(response_raw)
signature = outer_serializer.validated_data['signature']
serializer = AuthenticationChangePasswordInnerSerializer(
request.user.userinfo, data=response, context={'host': request.get_host()})
context = {'host': request.get_host(), 'supports_binary': True}
serializer = AuthenticationChangePasswordInnerSerializer(request.user.userinfo, data=response, context=context)
serializer.is_valid(raise_exception=True)
bad_login_response = self.validate_login_request(

@ -4,5 +4,6 @@ django-cors-headers
django-fullurl
djangorestframework
drf-nested-routers
msgpack
psycopg2-binary
pynacl

@ -15,6 +15,7 @@ django==3.0.3 # via -r requirements.in/base.txt, django-anymail, dja
djangorestframework==3.11.0 # via -r requirements.in/base.txt, drf-nested-routers
drf-nested-routers==0.91 # via -r requirements.in/base.txt
idna==2.8 # via requests
msgpack==1.0.0 # via -r requirements.in/base.txt
psycopg2-binary==2.8.4 # via -r requirements.in/base.txt
pycparser==2.20 # via cffi
pynacl==1.3.0 # via -r requirements.in/base.txt

Loading…
Cancel
Save