Initial mfa support (for internal users) #93591

Merged
Oleg-Komarov merged 46 commits from mfa into main 2024-08-29 11:44:06 +02:00
Showing only changes of commit 0326c78568 - Show all commits

View File

@ -0,0 +1,86 @@
from unittest.mock import patch
import re
from django.test.client import Client
from django.test import TestCase
from django.utils import timezone
from bid_main.tests.factories import UserFactory
from mfa.models import devices_for_user
@patch(
'django.contrib.auth.base_user.AbstractBaseUser.check_password',
new=lambda _, pwd: pwd == 'hunter2',
)
@patch(
'django_otp.oath.TOTP.verify',
new=lambda _, token, *args, **kwargs: int(token) == 123456,
)
class TestMfaRequredIfConfigured(TestCase):
def setUp(self):
self.user = UserFactory(
confirmed_email_at=timezone.now(),
privacy_policy_agreed=timezone.now(),
)
def test_no_mfa(self):
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
# showing account page, after a redirect
self.assertEqual(response.status_code, 200)
self.assertContains(response, '<h2>Account</h2>')
def test_setup_totp(self):
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
self.assertEqual(response.status_code, 200)
response = client.get('/mfa/totp/')
match = re.search(
r'input type="hidden" name="key" value="([^"]+)"', str(response.content)
)
key = match.group(1)
match = re.search(
r'input type="hidden" name="signature" value="([^"]+)"', str(response.content)
)
signature = match.group(1)
response = client.post(
'/mfa/totp/',
{'name': 'test totp device', 'code': '123456', 'key': key, 'signature': signature},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertEqual(devices_for_user(self.user)[0].name, 'test totp device')
# emulating a different browser
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
self.assertEqual(response.status_code, 200)
# haven't reached the account page
self.assertNotContains(response, '<h2>Account</h2>')
self.assertContains(response, 'autocomplete="one-time-code"')
match = re.search(
r'input type="hidden" name="otp_device" value="([^"]+)"', str(response.content)
)
otp_device = match.group(1)
response = client.post(
'/login',
{'otp_device': otp_device, 'otp_token': '123456'},
follow=True,
)
# have reached the account page
self.assertEqual(response.status_code, 200)
self.assertContains(response, '<h2>Account</h2>')