__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"
import datetime
from django.urls import reverse
from django.test import TestCase, Client
from mock import Mock, patch
from scipost.factories import UserFactory, TOTPDeviceFactory
from scipost.totp import TOTPVerification
# Mock random test time of which the test values are know
# Secret key: 'XTNHYG5OJPQ7ZRDC'
# Valid token: '451977'
mock_time = Mock()
mock_time.return_value = datetime.datetime(2019, 12, 8, 11, 1, 1).timestamp()
[docs]class TOTPVerificationTest(TestCase):
"""
Test the scipost.totp.TOTPVerification util.
"""
valid_secret_key = 'XTNHYG5OJPQ7ZRDC'
valid_token = '451977'
[docs] def setUp(self):
super().setUp()
self.client = Client()
[docs] @classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.password = 'super_secret_123'
cls.user = UserFactory(contrib=None)
cls.user.set_password(cls.password)
cls.user.save()
[docs] @patch('time.time', mock_time)
def test_proper_return_classmethod(self):
"""Test if valid secret_key/time/token combinations return True."""
self.assertTrue(TOTPVerification.verify_token(self.valid_secret_key, self.valid_token))
self.assertFalse(TOTPVerification.verify_token('XTNHYG5OJPQ7ZRDX', self.valid_token))
self.assertFalse(TOTPVerification.verify_token(self.valid_secret_key, '4519000'))
[docs] def test_2fa_workaround_closed(self):
"""
Test if the admin login form is disabled. It's an easy workaround for 2FA.
"""
# Test GET request
self.client.logout()
response = self.client.get('/admin')
self.assertEqual(response.status_code, 301) # Disabled by permanent redirect
# Test POST request
response = self.client.post('/admin', follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/'
})
self.assertNotEqual(response.context['user'], self.user)
self.assertEqual(response.redirect_chain[0][0], '/admin/')
self.assertEqual(response.redirect_chain[0][1], 301) # Check if immediately redirected
[docs] @patch('time.time', mock_time)
def test_proper_login_procedure(self):
"""Test if CBV fails gently if not used properly."""
login_url = reverse('scipost:login')
response = self.client.get(login_url)
self.assertEqual(response.status_code, 200)
# Does posting work?
response = self.client.post(
login_url, follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/',
'code': ''
})
self.assertEqual(response.context['user'], self.user)
self.assertEqual(response.redirect_chain[-1][0], '/') # Check if eventually redirected
self.assertEqual(response.redirect_chain[-1][1], 302)
# Logout for next step
self.client.logout()
# Check if a simple login without code fails if device is set up.
TOTPDeviceFactory.create(user=self.user, token=self.valid_secret_key)
response = self.client.post(
login_url, follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/',
'code': ''
})
self.assertNotEqual(response.context['user'], self.user)
# Check if login fails with invalid code
response = self.client.post(
login_url, follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/',
'code': '912334'
})
self.assertNotEqual(response.context['user'], self.user)
response = self.client.post(
login_url, follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/',
'code': '000000'
})
self.assertNotEqual(response.context['user'], self.user)
# Check if login *WORKS* with a valid code.
response = self.client.post(
login_url, follow=True,
data={
'username': self.user.username,
'password': self.password,
'next': '/',
'code': self.valid_token
})
self.assertEqual(response.context['user'], self.user)