Skip to content

Commit

Permalink
Merge pull request #713 from moggers87/699-yubikey-cookie-error
Browse files Browse the repository at this point in the history
Fix  'RemoteYubikeyDevice' object has no attribute 'throttle_reset'
  • Loading branch information
moggers87 authored May 24, 2024
2 parents 8bcfc21 + 25e5e5d commit 2611ef5
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
31 changes: 31 additions & 0 deletions tests/test_views_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from unittest import mock

from django.conf import settings
from django.core.signing import BadSignature
from django.shortcuts import resolve_url
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings
Expand Down Expand Up @@ -885,3 +886,33 @@ def test_phonedevice_with_remember_cookie(self, mock_signal, fake):
'login_view-current_step': 'auth'})

self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))

@override_settings(TWO_FACTOR_REMEMBER_COOKIE_AGE=60 * 60)
def test_remember_cookie_with_device_without_throttle(self):
self._post({'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})

self._post({'token-otp_token': totp_str(self.device.bin_key),
'login_view-current_step': 'token',
'token-remember': 'on'})
self.client.post(reverse('logout'))

# mock device_for_user
with mock.patch("two_factor.views.core.devices_for_user") as devices_for_user_mock, \
mock.patch("two_factor.views.core.validate_remember_device_cookie") as validate_mock:
device_mock = mock.Mock(spec=["verify_is_allowed", "persistent_id", "user_id"])
device_mock.persistent_id = 1
device_mock.verify_is_allowed.return_value = [True, {}]
devices_for_user_mock.return_value = [device_mock]
validate_mock.return_value = True
response = self._post({'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
self.assertRedirects(response, reverse(settings.LOGIN_REDIRECT_URL), fetch_redirect_response=False)
self.client.post(reverse('logout'))
validate_mock.side_effect = BadSignature()
response = self._post({'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
self.assertContains(response, 'Token:')
30 changes: 29 additions & 1 deletion tests/test_yubikey.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import resolve_url
from django.test import TestCase
from django.test import TestCase, override_settings
from django.urls import reverse

from .utils import UserMixin
Expand Down Expand Up @@ -131,3 +131,31 @@ def test_no_otp_yubikey_installed(self, *args):
msg = "'otp_yubikey' must be installed to be able to use the yubikey plugin."
with self.assertRaisesMessage(ImproperlyConfigured, msg):
apps.get_app_config('yubikey').ready()

@override_settings(TWO_FACTOR_REMEMBER_COOKIE_AGE=60 * 60)
@patch('otp_yubikey.models.RemoteYubikeyDevice.verify_token')
def test_login_with_remember_cookie(self, verify_token):
user = self.create_user()
verify_token.return_value = True
service = ValidationService.objects.create(name='default', param_sl='', param_timeout='')
user.remoteyubikeydevice_set.create(service=service, name='default')

response = self.client.post(reverse('two_factor:login'),
data={'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
# Should call verify_token
token = 'cjikftknbiktlitnbltbitdncgvrbgic'
response = self.client.post(reverse('two_factor:login'),
data={'token-otp_token': token,
'login_view-current_step': 'token',
'token-remember': 'on'})
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
verify_token.assert_called_with(token)

self.client.post(reverse('logout'))
response = self.client.post(reverse('two_factor:login'),
data={'auth-username': '[email protected]',
'auth-password': 'secret',
'login_view-current_step': 'auth'})
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
4 changes: 2 additions & 2 deletions two_factor/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,10 @@ def remember_agent(self):
otp_device_id=device.persistent_id
):
user.otp_device = device
device.throttle_reset()
getattr(device, "throttle_reset", lambda: None)()
return True
except BadSignature:
device.throttle_increment()
getattr(device, "throttle_increment", lambda: None)()
# Remove remember cookies with invalid signature to omit unnecessary throttling
self.cookies_to_delete.append(key)
return False
Expand Down

0 comments on commit 2611ef5

Please sign in to comment.