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 15f3d6fc5b - Show all commits

View File

@ -18,7 +18,7 @@ from mfa.models import EncryptedTOTPDevice, devices_for_user
'django_otp.oath.TOTP.verify',
new=lambda _, token, *args, **kwargs: int(token) == 123456,
)
class TestMfaRequredIfConfigured(TestCase):
class TestMfa(TestCase):
def setUp(self):
self.user = UserFactory(
confirmed_email_at=timezone.now(),
@ -134,3 +134,112 @@ class TestMfaRequredIfConfigured(TestCase):
self.assertEqual(response.status_code, 302)
response = client.get(reverse('bid_main:mfa'))
self.assertContains(response, '9 recovery codes remaining')
# test that can't reuse the same code, repeating the steps
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
response = client.get('/login?use_recovery=1')
match = re.search(
r'input type="hidden" name="otp_device" value="([^"]+)"', str(response.content)
)
otp_device = match.group(1)
response = client.post(
'/login?use_recovery=1',
{'otp_device': otp_device, 'otp_token': recovery_code},
)
self.assertEqual(response.status_code, 200)
def test_disable_mfa(self):
# shortcut: create a totp device via a model
EncryptedTOTPDevice.objects.create(encrypted_key='00', key='', name='totp', user=self.user)
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
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,
)
client.post(reverse('bid_main:mfa_disable'), {'disable_mfa_confirm': 'True'})
# no mfa requried now
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
self.assertContains(response, '<h2>Account</h2>')
def test_remember_device(self):
# shortcut: create a totp device via a model
EncryptedTOTPDevice.objects.create(encrypted_key='00', key='', name='totp', user=self.user)
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
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', 'otp_trust_agent': 'True'},
follow=True,
)
client.get('/logout', follow=True)
# no mfa requried now, same client
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
self.assertContains(response, '<h2>Account</h2>')
def test_dont_remember_device(self):
# shortcut: create a totp device via a model
EncryptedTOTPDevice.objects.create(encrypted_key='00', key='', name='totp', user=self.user)
client = Client()
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
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', 'otp_trust_agent': ''},
follow=True,
)
client.get('/logout', follow=True)
# no mfa requried now, same client
response = client.post(
'/login',
{'username': self.user.email, 'password': 'hunter2'},
follow=True,
)
self.assertNotContains(response, '<h2>Account</h2>')