Controlling TOTP Authetication

This commit is contained in:
Mohamed El-Kalioby
2021-06-24 18:42:33 +03:00
parent 0b83758625
commit ca49e1623d
8 changed files with 91 additions and 29 deletions

View File

@@ -6,12 +6,12 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('mfa', '0011_auto_20210530_0622'),
("mfa", "0011_auto_20210530_0622"),
]
operations = [
migrations.RenameModel(
old_name='User_Keys',
new_name='UserKey',
old_name="User_Keys",
new_name="UserKey",
),
]

View File

@@ -0,0 +1,35 @@
# Generated by Django 2.2 on 2021-06-24 15:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("mfa", "0012_rename_user_keys_userkey"),
]
operations = [
migrations.CreateModel(
name="OTPTracker",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("actor", models.CharField(max_length=50)),
("value", models.CharField(max_length=6)),
("success", models.BooleanField(blank=True)),
("done_on", models.DateTimeField(auto_now=True)),
],
),
migrations.AddIndex(
model_name="otptracker",
index=models.Index(fields=["actor"], name="mfa_otptrac_usernam_1f423f_idx"),
),
]

View File

@@ -33,11 +33,13 @@ class UserKey(models.Model):
class OTPTracker(models.Model):
username = models.CharField(max_length=50)
value = models.CharField(max_length = 6)
actor = models.CharField(
max_length=50, help_text="Username"
) # named this way for indexing purpose.
value = models.CharField(max_length=6)
success = models.BooleanField(blank=True)
done_on = models.DateTimeField(auto_now=True)
class Meta:
app_label = 'mfa'
indexes = [models.Index(fields=['username'])]
app_label = "mfa"
indexes = [models.Index(fields=["actor"])]

View File

@@ -28,7 +28,7 @@
{% csrf_token %}
{% if invalid %}
<div class="alert alert-danger">
Sorry, The provided token is not valid.
{{ invalid_msg }}
</div>
{% endif %}
{% if quota %}

View File

@@ -16,17 +16,34 @@ from .views import login
def verify_login(request, username, token):
FAILURE_LIMIT = getattr("settings", "MFA_TOTP_FAILURE_LIMIT", 3)
start_time = timezone.now() + datetime.timedelta(
minutes=-1 * getattr(settings, "MFA_TOTP_FAILURE_WINDOW", 5)
)
if (
OTPTracker.objects.filter(
done_on__gt=start_time, actor=username, success=0
).count()
>= FAILURE_LIMIT
):
return [
False,
"Using this method is temporarily suspended on your account, use another method, or later again later ",
]
for key in UserKey.objects.filter(username=username, key_type="TOTP"):
totp = pyotp.TOTP(key.properties["secret_key"])
if totp.verify(token, valid_window=30):
if OTPTracker.objects.filter(username=username, value=token).exists():
return [False, "Used Before, please generate another token"]
TOTP_Tracker.objects.create(username=username,value=token, success=True)
if OTPTracker.objects.filter(actor=username, value=token).exists():
return [
False,
"This code is used before, please generate another token",
]
OTPTracker.objects.create(actor=username, value=token, success=True)
key.last_used = timezone.now()
key.save()
return [True, key.id]
TOTP_Tracker.objects.create(username = username, value = token, success = False)
return [False,"Invalid Token"]
OTPTracker.objects.create(actor=username, value=token, success=False)
return [False, "Invalid Token"]
def recheck(request):
@@ -68,7 +85,7 @@ def auth(request):
return render(request, "TOTP/Auth.html", context)
def getToken(request):
def get_token(request):
secret_key = pyotp.random_base32()
totp = pyotp.TOTP(secret_key)
request.session["new_mfa_answer"] = totp.now()