Initial mfa support (for internal users) #93591
86
bid_main/tests/test_mfa.py
Normal file
86
bid_main/tests/test_mfa.py
Normal 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>')
|
Loading…
Reference in New Issue
Block a user