import pyotp import otpauth from rest_framework import serializers, exceptions from otpauth.models import OTPSeed # For accessing / modifying the data -- currently unused class OTPSerializer(serializers.ModelSerializer): class Meta: model = OTPSeed fields = ('name', 'realm', 'seed') read_only_fields = ('seed',) def create(self, validated_data): validated_data['seed'] = pyotp.random_base32() return OTPSeed.objects.create(**validated_data) class TokenSerializer(serializers.Serializer): """ This class is mainly / only used for authentication""" auth_name = serializers.CharField(max_length=128) auth_token = serializers.CharField(max_length=128) auth_realm = serializers.CharField(max_length=128) token_name = 'auth_token' name_name = 'auth_name' realm_name = 'auth_realm' def save(self): auth_token = self.validated_data.get(self.token_name) auth_name = self.validated_data.get(self.name_name) auth_realm = self.validated_data.get(self.realm_name) # only 2 special realms can login if not auth_realm in ["ungleich-admin", "ungleich-auth" ]: raise exceptions.AuthenticationFailed() print("auth: [{}]{}@'{}' {} + {})".format(self.name_name, auth_name, auth_realm, auth_token, self.validated_data)) # 1. Verify that the connection might authenticate try: db_instance = otpauth.models.OTPSeed.objects.get(name=auth_name, realm=auth_realm) except (OTPSeed.MultipleObjectsReturned, OTPSeed.DoesNotExist): print("does not exist") raise exceptions.AuthenticationFailed() totp = pyotp.TOTP(db_instance.seed) print("calculated token = {}".format(totp.now())) if not totp.verify(auth_token, valid_window=3): raise exceptions.AuthenticationFailed() return (db_instance, auth_token) # For verifying somebody else's token class VerifySerializer(TokenSerializer): name = serializers.CharField(max_length=128) token = serializers.CharField(max_length=128) realm = serializers.CharField(max_length=128) token_name = 'token' name_name = 'name' realm_name = 'realm' def save(self): auth_realm = self.validated_data.get("auth_realm") if not auth_realm == "ungleich-auth": raise exceptions.AuthenticationFailed() # Do the authentication part super().save()