Skip to content

Commit

Permalink
issue 145 alternative named static backup device use fix
Browse files Browse the repository at this point in the history
  • Loading branch information
nnseva committed Oct 14, 2022
1 parent 51b7fc2 commit 848e88d
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
34 changes: 34 additions & 0 deletions tests/test_views_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,40 @@ def test_with_backup_token(self, mock_signal):
# Check that the signal was fired.
mock_signal.assert_called_with(sender=mock.ANY, request=mock.ANY, user=user, device=device)

@mock.patch('two_factor.views.core.signals.user_verified.send')
def test_with_alter_backup_token(self, mock_signal):
user = self.create_user()
user.totpdevice_set.create(name='default', key=random_hex())
device = user.staticdevice_set.create(name='alter')
device.token_set.create(token='abcdef123')

# Backup phones should be listed on the login form
response = self._post({'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
self.assertContains(response, 'Backup Token')

# Should be able to go to backup tokens step in wizard
response = self._post({'wizard_goto_step': 'backup'})
self.assertContains(response, 'backup tokens')

# Wrong codes should not be accepted
response = self._post({'backup-otp_token': 'WRONG',
'login_view-current_step': 'backup'})
self.assertEqual(response.context_data['wizard']['form'].errors,
{'__all__': ['Invalid token. Please make sure you '
'have entered it correctly.']})
# static devices are throttled
device.throttle_reset()

# Valid token should be accepted.
response = self._post({'backup-otp_token': 'abcdef123',
'login_view-current_step': 'backup'})
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))

# Check that the signal was fired.
mock_signal.assert_called_with(sender=mock.ANY, request=mock.ANY, user=user, device=device)

@mock.patch('two_factor.views.utils.logger')
def test_reset_wizard_state(self, mock_logger):
self.create_user()
Expand Down
23 changes: 23 additions & 0 deletions tests/test_yubikey.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,29 @@ def test_show_correct_label(self):
self.assertNotContains(response, 'YubiKey:')
self.assertContains(response, 'Token:')

def test_show_correct_label_alter_backup(self):
"""
The token form replaces the input field when the user's device is a
YubiKey. However when the user decides to enter a backup token, the
normal backup token form should be shown. Refs #50.
"""
user = self.create_user()
service = ValidationService.objects.create(name='default', param_sl='', param_timeout='')
user.remoteyubikeydevice_set.create(service=service, name='default')
backup = user.staticdevice_set.create(name='alter')
backup.token_set.create(token='RANDOM')

response = self.client.post(reverse('two_factor:login'),
data={'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
self.assertContains(response, 'YubiKey:')

response = self.client.post(reverse('two_factor:login'),
data={'wizard_goto_step': 'backup'})
self.assertNotContains(response, 'YubiKey:')
self.assertContains(response, 'Token:')

def test_missing_management_data(self):
# missing management data
response = self.client.post(reverse('two_factor:login'),
Expand Down
17 changes: 7 additions & 10 deletions two_factor/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,7 @@ def get_device(self, step=None):
self.device_cache = device
break
if step == 'backup':
try:
self.device_cache = self.get_user().staticdevice_set.get(name='backup')
except StaticDevice.DoesNotExist:
pass
self.device_cache = self.get_user().staticdevice_set.all().first()
if not self.device_cache:
self.device_cache = default_device(self.get_user())
return self.device_cache
Expand Down Expand Up @@ -322,11 +319,8 @@ def get_context_data(self, form, **kwargs):
context['other_devices'] = [
phone for phone in backup_phones(self.get_user())
if phone != self.get_device()]
try:
context['backup_tokens'] = self.get_user().staticdevice_set\
.get(name='backup').token_set.count()
except StaticDevice.DoesNotExist:
context['backup_tokens'] = 0
context['backup_tokens'] = self.get_user().staticdevice_set\
.all().values('token_set__token').count()

if getattr(settings, 'LOGOUT_REDIRECT_URL', None):
context['cancel_url'] = resolve_url(settings.LOGOUT_REDIRECT_URL)
Expand Down Expand Up @@ -580,7 +574,10 @@ class BackupTokensView(FormView):
number_of_tokens = 10

def get_device(self):
return self.request.user.staticdevice_set.get_or_create(name='backup')[0]
device = self.request.user.staticdevice_set.all().first()
if not device:
device = self.request.user.staticdevice_set.create(name='backup')
return device

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand Down

0 comments on commit 848e88d

Please sign in to comment.