Merge branch 'master' into 'master'
Decouple config and add logging See merge request ungleich-public/ungleich-otp!1
This commit is contained in:
commit
84afaaa56d
8 changed files with 86 additions and 8 deletions
3
.env.sample
Normal file
3
.env.sample
Normal file
|
@ -0,0 +1,3 @@
|
|||
SECRET_KEY=ldskjflkdsnejnjsdnf
|
||||
DEBUG=False
|
||||
ENABLE_DEBUG_LOG=True
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
|||
.idea/
|
||||
venv/
|
||||
db.sqlite3
|
||||
aux/
|
||||
__pycache__/
|
||||
static/
|
||||
|
|
2
logs/.gitignore
vendored
Normal file
2
logs/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -2,6 +2,10 @@ from django.db import models
|
|||
from django.contrib.auth.models import AbstractUser
|
||||
from rest_framework import exceptions
|
||||
from rest_framework import authentication
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OTPSeed(AbstractUser):
|
||||
|
@ -27,17 +31,20 @@ from otpauth.serializer import TokenSerializer
|
|||
|
||||
class OTPAuthentication(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
logger.debug("in authenticate {}".format(json.dumps(request.data)))
|
||||
serializer = TokenSerializer(data=request.data)
|
||||
|
||||
if serializer.is_valid():
|
||||
instance, token = serializer.save()
|
||||
else:
|
||||
logger.error("serializer is invalid")
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
# not dealing with admin realm -> can only be auth [see serializer]
|
||||
if not instance.realm == "ungleich-admin":
|
||||
if not request.path == "/ungleichotp/verify/":
|
||||
logger.debug("request.path is not /ungleichotp/verify/")
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
# print("AUTH DONE: {} - {}".format(request.path, instance))
|
||||
logger.debug("AUTH DONE: {} - {}".format(request.path, instance))
|
||||
return (instance, token)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import logging
|
||||
import pyotp
|
||||
import otpauth
|
||||
from rest_framework import serializers, exceptions
|
||||
from otpauth.models import OTPSeed
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# For accessing / modifying the data -- currently unused
|
||||
class OTPSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
|
@ -32,21 +35,33 @@ class TokenSerializer(serializers.Serializer):
|
|||
|
||||
# only 2 special realms can login
|
||||
if not auth_realm in ["ungleich-admin", "ungleich-auth" ]:
|
||||
logger.error("Auth-realm is neither ungleich-admin "
|
||||
"nor ungleich-auth".format()
|
||||
)
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
print("auth: [{}]{}@'{}' {} + {})".format(self.name_name, auth_name, auth_realm, auth_token, self.validated_data))
|
||||
logger.debug("auth: [{}]{}@'{}' {} + {})".format(
|
||||
self.name_name, auth_name, auth_realm,
|
||||
auth_token, self.validated_data
|
||||
))
|
||||
|
||||
# 1. Verify that the connection might authenticate
|
||||
try:
|
||||
logger.debug("Checking in db for name:{} & realm:{}".format(
|
||||
auth_name, auth_realm
|
||||
))
|
||||
db_instance = otpauth.models.OTPSeed.objects.get(name=auth_name, realm=auth_realm)
|
||||
except (OTPSeed.MultipleObjectsReturned, OTPSeed.DoesNotExist):
|
||||
print("does not exist")
|
||||
logger.error("OTPSeed name: {}, realm: {} does not exist".format(
|
||||
auth_name, auth_realm
|
||||
))
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
logger.debug("Found seed: {}".format(db_instance.seed))
|
||||
totp = pyotp.TOTP(db_instance.seed)
|
||||
print("calculated token = {}".format(totp.now()))
|
||||
logger.debug("calculated token = {}".format(totp.now()))
|
||||
|
||||
if not totp.verify(auth_token, valid_window=3):
|
||||
logger.error("totp not verified")
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
return (db_instance, auth_token)
|
||||
|
@ -65,6 +80,7 @@ class VerifySerializer(TokenSerializer):
|
|||
auth_realm = self.validated_data.get("auth_realm")
|
||||
|
||||
if not auth_realm == "ungleich-auth":
|
||||
logger.error("Auth-realm is not ungleich-auth")
|
||||
raise exceptions.AuthenticationFailed()
|
||||
|
||||
# Do the authentication part
|
||||
|
|
|
@ -7,6 +7,11 @@ from rest_framework.response import Response
|
|||
from django.http import JsonResponse
|
||||
from otpauth.serializer import VerifySerializer, OTPSerializer, TokenSerializer
|
||||
from otpauth.models import OTPSeed
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OTPVerifyViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = OTPSerializer
|
||||
|
@ -20,7 +25,7 @@ class OTPVerifyViewSet(viewsets.ModelViewSet):
|
|||
Now we inspect the payload and return ok,
|
||||
if they also verify
|
||||
"""
|
||||
|
||||
logger.debug("in verify {}".format(json.dumps(request.data)))
|
||||
serializer = VerifySerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pyotp>=2.2.6
|
||||
django>=2.1.2
|
||||
djangorestframework
|
||||
python-decouple>=3.1
|
||||
|
||||
# DB
|
||||
psycopg2
|
||||
|
|
|
@ -10,6 +10,8 @@ For the full list of settings and their values, see
|
|||
https://docs.djangoproject.com/en/2.1/ref/settings/
|
||||
"""
|
||||
|
||||
from decouple import config, Csv
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
|
@ -20,7 +22,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'h^*!&u7yaac_6t02kk4de%$aagp6_j#+_wnw3@rqu6os0tlv#r'
|
||||
SECRET_KEY = config('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
|
||||
|
@ -129,7 +131,7 @@ DEBUG_DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
DEBUG = False
|
||||
DEBUG = config('DEBUG', False, cast=bool)
|
||||
ALLOWED_HOSTS = [
|
||||
".ungleich.ch"
|
||||
]
|
||||
|
@ -146,6 +148,45 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
LOGGING = {
|
||||
'disable_existing_loggers': False,
|
||||
'version': 1,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': '%(asctime)s %(levelname)s %(name)s: %(message)s'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'default': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': 'logs/debug.log',
|
||||
'maxBytes': 1024*1024*5,
|
||||
'backupCount': 10,
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if config('ENABLE_DEBUG_LOG', cast=bool, default=False):
|
||||
loggers_dict = {}
|
||||
modules_to_log_list = config(
|
||||
'MODULES_TO_LOG', default='django', cast=Csv()
|
||||
)
|
||||
for custom_module in modules_to_log_list:
|
||||
logger_item = {
|
||||
custom_module: {
|
||||
'handlers': ['default'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': True
|
||||
}
|
||||
}
|
||||
loggers_dict.update(logger_item)
|
||||
|
||||
LOGGING['loggers'] = loggers_dict
|
||||
|
||||
|
||||
if "DEBUG" in os.environ:
|
||||
|
|
Loading…
Reference in a new issue