From e42770e852993a285c5b5e07b2bd958c8d6e0d29 Mon Sep 17 00:00:00 2001 From: Mohamed ElKalioby Date: Wed, 7 Sep 2022 09:30:23 +0300 Subject: [PATCH] Added MFRENAMEMETHOD, MFA_REDIRECT_USER_TO_LAST_METHOD, Alot of theme fixes --- mfa/FIDO2.py | 2 +- mfa/recovery.py | 17 ++++++++++------ mfa/templates/FIDO2/recheck.html | 6 +++--- mfa/templates/MFA.html | 30 ++++++++++++++-------------- mfa/templates/select_mfa_method.html | 13 ++++++------ mfa/views.py | 13 +++++++++--- 6 files changed, 46 insertions(+), 35 deletions(-) diff --git a/mfa/FIDO2.py b/mfa/FIDO2.py index dcdf9f2..752a5a2 100644 --- a/mfa/FIDO2.py +++ b/mfa/FIDO2.py @@ -137,7 +137,7 @@ def authenticate_complete(request): except: pass return HttpResponse(simplejson.dumps({'status': "ERR", - "message": excep.message}), + "message": str(excep)}), content_type = "application/json") if request.session.get("mfa_recheck", False): diff --git a/mfa/recovery.py b/mfa/recovery.py index 5b99e15..38f4b9a 100644 --- a/mfa/recovery.py +++ b/mfa/recovery.py @@ -9,6 +9,9 @@ import simplejson import random import string import datetime +from django.utils import timezone + +USER_FRIENDLY_NAME = "Recovery Codes" class Hash(PBKDF2PasswordHasher): algorithm = 'pbkdf2_sha256_custom' @@ -38,6 +41,7 @@ def genTokens(request): hashedKeys.append(hashedToken) clearKeys.append(token) uk=User_Keys() + uk.username = request.user.username uk.properties={"secret_keys":hashedKeys, "salt":salt} uk.key_type="RECOVERY" @@ -51,10 +55,11 @@ def verify_login(request, username, token): secret_keys = key.properties["secret_keys"] salt = key.properties["salt"] hashedToken = make_password(token, salt, "pbkdf2_sha256_custom") - for i in range(len(secret_keys)): - if hashedToken == secret_keys[i]: + for i,token in enumerate(secret_keys): + if hashedToken == token: secret_keys.pop(i) key.properties["secret_keys"] = secret_keys + key.last_used= timezone.now() key.save() return [True, key.id, len(secret_keys) == 0] return [False] @@ -89,10 +94,10 @@ def auth(request): resBackup=verify_login(request, request.session["base_username"], token=request.POST["recovery"]) if resBackup[0]: mfa = {"verified": True, "method": "RECOVERY","id":resBackup[1], "lastBackup":resBackup[2]} - if getattr(settings, "MFA_RECHECK", False): - mfa["next_check"] = datetime.datetime.timestamp((datetime.datetime.now() - + datetime.timedelta( - seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX)))) + # if getattr(settings, "MFA_RECHECK", False): + # mfa["next_check"] = datetime.datetime.timestamp((datetime.datetime.now() + # + datetime.timedelta( + # seconds=random.randint(settings.MFA_RECHECK_MIN, settings.MFA_RECHECK_MAX)))) request.session["mfa"] = mfa if resBackup[2]: #If the last bakup code has just been used, we return a response insead of redirecting to login diff --git a/mfa/templates/FIDO2/recheck.html b/mfa/templates/FIDO2/recheck.html index 0b128bf..c44db3a 100644 --- a/mfa/templates/FIDO2/recheck.html +++ b/mfa/templates/FIDO2/recheck.html @@ -3,7 +3,7 @@
-
+
Security Key @@ -35,10 +35,10 @@
-
+
{% if request.session.mfa_methods|length > 1 %} - Select Another Method + Select Another Method {% endif %}
diff --git a/mfa/templates/MFA.html b/mfa/templates/MFA.html index cd57c11..afcc59d 100644 --- a/mfa/templates/MFA.html +++ b/mfa/templates/MFA.html @@ -45,31 +45,31 @@
-
+ -
+

@@ -86,11 +86,11 @@ {% for key in keys %} - + - + - + {% if key.key_type in HIDE_DISABLE %} {% else %} @@ -106,11 +106,11 @@ {% if "RECOVERY" not in UNALLOWED_AUTHEN_METHODS %} - - - - - + + + + + diff --git a/mfa/templates/select_mfa_method.html b/mfa/templates/select_mfa_method.html index 22d15f9..aa59acb 100644 --- a/mfa/templates/select_mfa_method.html +++ b/mfa/templates/select_mfa_method.html @@ -1,11 +1,10 @@ {% extends "mfa_auth_base.html" %} {% block content %} -

-
+
Select Second Verification Method @@ -15,11 +14,11 @@ {% for method in request.session.mfa_methods %}
  • - {% if method == "TOTP" %}Authenticator App - {% elif method == "Email" %}Send OTP by Email - {% elif method == "U2F" %}Secure Key - {% elif method == "FIDO2" %}FIDO2 Secure Key - {% elif method == "RECOVERY" %}Recovery Code + {% if method == "TOTP" %}{% if 'TOTP' in RENAME_METHODS %}{{ RENAME_METHODS.TOTP }}{% else %}Authenticator App{% endif %} + {% elif method == "Email" %}{% if 'Email' in RENAME_METHODS %}{{ RENAME_METHODS.Email }}{% else %}Send OTP by Email{% endif %} + {% elif method == "U2F" %}{% if 'U2F' in RENAME_METHODS %}{{ RENAME_METHODS.U2F }}{% else %}Secure Key{% endif %} + {% elif method == "FIDO2" %}{% if 'FIDO2' in RENAME_METHODS %}{{ RENAME_METHODS.FIDO2 }}{% else %}FIDO2 Secure Key{% endif %} + {% elif method == "RECOVERY" %}{% if 'RECOVERY' in RENAME_METHODS %}{{ RENAME_METHODS.RECOVERY }}{% else %}Recovery Code{% endif %} {% endif %}
  • {% endfor %} diff --git a/mfa/views.py b/mfa/views.py index 7eecc6c..b8fe3aa 100644 --- a/mfa/views.py +++ b/mfa/views.py @@ -1,3 +1,5 @@ +import importlib + from django.shortcuts import render from django.http import HttpResponse,HttpResponseRedirect from .models import * @@ -16,13 +18,15 @@ from user_agents import parse def index(request): keys=[] context={"keys":User_Keys.objects.filter(username=request.user.username),"UNALLOWED_AUTHEN_METHODS":settings.MFA_UNALLOWED_METHODS - ,"HIDE_DISABLE":getattr(settings,"MFA_HIDE_DISABLE",[])} + ,"HIDE_DISABLE":getattr(settings,"MFA_HIDE_DISABLE",[]),'RENAME_METHODS':getattr(settings,'MFA_RENAME_METHODS',{})} for k in context["keys"]: - if k.key_type =="Trusted Device" : + k.name = getattr(settings,'MFA_RENAME_METHODS',{}).get(k.key_type,k.key_type) + if k.key_type =="Trusted Device": setattr(k,"device",parse(k.properties.get("user_agent","-----"))) elif k.key_type == "FIDO2": setattr(k,"device",k.properties.get("type","----")) elif k.key_type == "RECOVERY": + context["recovery"] = k continue keys.append(k) context["keys"]=keys @@ -42,10 +46,13 @@ def verify(request,username): if len(methods)==1: return HttpResponseRedirect(reverse(methods[0].lower()+"_auth")) + if getattr(settings,"MFA_ALWAYS_GO_TO_LAST_METHOD",False): + keys = keys.exclude(last_used__isnull=True).order_by("last_used") + return HttpResponseRedirect(reverse(keys[0].key_type.lower() + "_auth")) return show_methods(request) def show_methods(request): - return render(request,"select_mfa_method.html", {}) + return render(request,"select_mfa_method.html", {'RENAME_METHODS':getattr(settings,'MFA_RENAME_METHODS',{})}) def reset_cookie(request): response=HttpResponseRedirect(settings.LOGIN_URL)
    {{ key.key_type }}{{ key.name }} {{ key.added_on }}{{ key.expires }}{% if key.expires %}{{ key.expires }}{% else %}N/A{% endif %} {% if key.device %}{{ key.device }}{% endif %}{{ key.last_used }}{% if key.last_used %}{{ key.last_used }}{% else %}Never{% endif %}{% if key.enabled %}On{% else %} Off{% endif %}
    RECOVERY{{ recovery.name }}{{ recovery.added_on }}N/AN/A{% if recovery.last_used %}{{ recovery.last_used }}{% else %}Never{% endif %} On