Skip to content

Commit

Permalink
fix: portal backend 376 (#150)
Browse files Browse the repository at this point in the history
* fix: new otp secret

* fix: new otp secret
  • Loading branch information
SKairinos authored Jan 20, 2025
1 parent 29e7116 commit 406a7ff
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
1 change: 1 addition & 0 deletions codeforlife/user/signals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"""

# NOTE: Need to import signals so they are discoverable by Django.
from .auth_factor import auth_factor__post_delete
from .teacher import teacher_receiver
from .user import user_receiver
25 changes: 25 additions & 0 deletions codeforlife/user/signals/auth_factor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
© Ocado Group
Created on 17/01/2025 at 15:55:22(+00:00).
"""

import pyotp
from django.db.models import signals
from django.dispatch import receiver

from ..models import AuthFactor

# pylint: disable=missing-function-docstring
# pylint: disable=unused-argument


@receiver(signals.post_delete, sender=AuthFactor)
def auth_factor__post_delete(sender, instance: AuthFactor, **kwargs):
# Create new secret to ensure secrets are not recycled.
if instance.type == AuthFactor.Type.OTP:
otp_secret = instance.user.userprofile.otp_secret
# Ensure the randomly generated new secret is different to the previous.
while otp_secret == instance.user.userprofile.otp_secret:
instance.user.userprofile.otp_secret = pyotp.random_base32()

instance.user.userprofile.save(update_fields=["otp_secret"])
28 changes: 28 additions & 0 deletions codeforlife/user/signals/auth_factor_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
© Ocado Group
Created on 17/01/2025 at 16:04:46(+00:00).
"""

from django.test import TestCase

from ..models import AuthFactor


# pylint: disable-next=missing-class-docstring
class TestAuthFactor(TestCase):
fixtures = ["school_2"]

def test_post_delete(self):
"""Deleting an otp-auth-factor assigns a new otp-secret to its user."""
auth_factor = AuthFactor.objects.filter(
type=AuthFactor.Type.OTP
).first()
assert auth_factor

userprofile = auth_factor.user.userprofile
otp_secret = userprofile.otp_secret

auth_factor.delete()

userprofile.refresh_from_db()
assert otp_secret != userprofile.otp_secret

0 comments on commit 406a7ff

Please sign in to comment.