2018-10-26 19:08:01 +00:00
|
|
|
from django.db import models
|
2018-11-17 20:45:53 +00:00
|
|
|
from django.contrib.auth.models import AbstractUser
|
2018-12-30 16:57:02 +00:00
|
|
|
from rest_framework import exceptions
|
|
|
|
from rest_framework import authentication
|
2019-02-10 22:52:52 +00:00
|
|
|
import json
|
|
|
|
import logging
|
2019-09-26 09:56:10 +00:00
|
|
|
import pyotp
|
2019-02-10 22:52:52 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2018-12-30 18:02:34 +00:00
|
|
|
|
2018-12-30 16:57:02 +00:00
|
|
|
|
2018-11-17 22:00:36 +00:00
|
|
|
class OTPSeed(AbstractUser):
|
2018-11-17 09:01:24 +00:00
|
|
|
id = models.AutoField(primary_key=True)
|
2018-11-17 08:42:34 +00:00
|
|
|
name = models.CharField(max_length=128)
|
|
|
|
realm = models.CharField(max_length=128)
|
2018-10-26 19:48:21 +00:00
|
|
|
seed = models.CharField(max_length=128)
|
2018-11-17 08:42:34 +00:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
unique_together = (('name', 'realm'),)
|
|
|
|
|
2018-12-30 21:51:34 +00:00
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
"""
|
|
|
|
inject username to ensure it stays unique / is setup at all
|
|
|
|
"""
|
2019-09-26 09:40:16 +00:00
|
|
|
if not self.is_superuser:
|
|
|
|
self.username = "{}@{}".format(self.name, self.realm)
|
|
|
|
else:
|
|
|
|
self.name = self.username
|
2019-09-26 09:56:10 +00:00
|
|
|
self.realm = "ungleich-admin"
|
|
|
|
self.seed = pyotp.random_base32()
|
2019-09-26 09:40:16 +00:00
|
|
|
|
2018-12-30 21:51:34 +00:00
|
|
|
super().save(*args, **kwargs)
|
2018-12-30 21:30:11 +00:00
|
|
|
|
2018-12-30 21:51:34 +00:00
|
|
|
def __str__(self):
|
|
|
|
return "'{}'@{} -- {}".format(self.name, self.realm, self.username)
|
2018-12-30 21:30:11 +00:00
|
|
|
|
2018-12-30 18:02:34 +00:00
|
|
|
from otpauth.serializer import TokenSerializer
|
|
|
|
|
2018-11-18 11:54:47 +00:00
|
|
|
class OTPAuthentication(authentication.BaseAuthentication):
|
|
|
|
def authenticate(self, request):
|
2019-02-10 22:52:52 +00:00
|
|
|
logger.debug("in authenticate {}".format(json.dumps(request.data)))
|
2018-11-18 11:54:47 +00:00
|
|
|
serializer = TokenSerializer(data=request.data)
|
|
|
|
|
|
|
|
if serializer.is_valid():
|
2018-12-30 23:46:29 +00:00
|
|
|
instance, token = serializer.save()
|
2018-11-18 11:54:47 +00:00
|
|
|
else:
|
2019-02-10 22:52:52 +00:00
|
|
|
logger.error("serializer is invalid")
|
2018-11-18 11:54:47 +00:00
|
|
|
raise exceptions.AuthenticationFailed()
|
|
|
|
|
2018-12-30 23:46:29 +00:00
|
|
|
# not dealing with admin realm -> can only be auth [see serializer]
|
|
|
|
if not instance.realm == "ungleich-admin":
|
|
|
|
if not request.path == "/ungleichotp/verify/":
|
2019-02-10 22:52:52 +00:00
|
|
|
logger.debug("request.path is not /ungleichotp/verify/")
|
2018-12-30 23:46:29 +00:00
|
|
|
raise exceptions.AuthenticationFailed()
|
|
|
|
|
2019-02-10 22:52:52 +00:00
|
|
|
logger.debug("AUTH DONE: {} - {}".format(request.path, instance))
|
2018-12-30 23:46:29 +00:00
|
|
|
return (instance, token)
|