From 2c8818ebc14968db9ad4af4d151f1b7437cb775a Mon Sep 17 00:00:00 2001 From: SKairinos Date: Mon, 20 Jan 2025 16:18:45 +0000 Subject: [PATCH] fix: create auth factor --- src/api/serializers/auth_factor.py | 5 +++++ src/api/serializers/auth_factor_test.py | 14 ++++++++++++++ src/api/views/auth_factor_test.py | 16 +++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/api/serializers/auth_factor.py b/src/api/serializers/auth_factor.py index 8a463fc7..cad99781 100644 --- a/src/api/serializers/auth_factor.py +++ b/src/api/serializers/auth_factor.py @@ -54,3 +54,8 @@ def validate(self, attrs): ) return attrs + + def create(self, validated_data): + validated_data["user_id"] = self.request.auth_user.id + validated_data.pop("otp", None) + return super().create(validated_data) diff --git a/src/api/serializers/auth_factor_test.py b/src/api/serializers/auth_factor_test.py index e50e8a12..a52b3e45 100644 --- a/src/api/serializers/auth_factor_test.py +++ b/src/api/serializers/auth_factor_test.py @@ -85,3 +85,17 @@ def test_validate__otp__required(self): attrs={"type": AuthFactor.Type.OTP.value}, error_code="otp__required", ) + + def test_create__otp(self): + """Can successfully enable an auth factor.""" + user = TeacherUser.objects.exclude( + auth_factors__type__in=["otp"] + ).first() + assert user + + self.assert_create( + validated_data={"type": AuthFactor.Type.OTP, "otp": "123456"}, + non_model_fields={"otp"}, + new_data={"user": user.id}, + context={"request": self.request_factory.post(user=user)}, + ) diff --git a/src/api/views/auth_factor_test.py b/src/api/views/auth_factor_test.py index 32461974..16f9bf6c 100644 --- a/src/api/views/auth_factor_test.py +++ b/src/api/views/auth_factor_test.py @@ -5,6 +5,7 @@ from unittest.mock import patch +import pyotp from codeforlife.permissions import AllowNone from codeforlife.tests import ModelViewSetTestCase from codeforlife.user.models import ( @@ -149,14 +150,23 @@ def test_list(self): def test_create__otp(self): """Can enable OTP.""" - teacher_user = TeacherUser.objects.filter( - auth_factors__isnull=True + teacher_user = TeacherUser.objects.exclude( + auth_factors__type__in=["otp"] ).first() assert teacher_user + # TODO: make "otp_secret" non-nullable and delete code block + teacher_user.userprofile.otp_secret = pyotp.random_base32() + teacher_user.userprofile.save(update_fields=["otp_secret"]) + # TODO: set password="password" on all user fixtures self.client.login_as(teacher_user, password="abc123") - self.client.create({"type": "otp"}) + self.client.create( + { + "type": AuthFactor.Type.OTP, + "otp": teacher_user.totp.now(), + } + ) def test_destroy(self): """Can disable an auth-factor."""