Skip to content

Commit 864d696

Browse files
PetrDlouhyclaudep
authored andcommitted
Fixed setup redirection regression
Regression in 4bd592c.
1 parent 0c31bbf commit 864d696

File tree

5 files changed

+45
-12
lines changed

5 files changed

+45
-12
lines changed

tests/test_views_login.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_valid_login(self, mock_signal):
3838
response = self._post({'auth-username': '[email protected]',
3939
'auth-password': 'secret',
4040
'login_view-current_step': 'auth'})
41-
self.assertRedirects(response, reverse('two_factor:setup'))
41+
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
4242

4343
# No signal should be fired for non-verified user logins.
4444
self.assertFalse(mock_signal.called)
@@ -53,6 +53,16 @@ def test_valid_login_with_custom_redirect(self):
5353
'login_view-current_step': 'auth'})
5454
self.assertRedirects(response, redirect_url)
5555

56+
def test_valid_login_non_class_based_redirect(self):
57+
redirect_url = reverse('plain')
58+
self.create_user()
59+
response = self.client.post(
60+
'%s?%s' % (reverse('two_factor:login'), 'next=' + redirect_url),
61+
{'auth-username': '[email protected]',
62+
'auth-password': 'secret',
63+
'login_view-current_step': 'auth'})
64+
self.assertRedirects(response, redirect_url)
65+
5666
def test_valid_login_with_custom_post_redirect(self):
5767
redirect_url = reverse('two_factor:setup')
5868
self.create_user()
@@ -80,8 +90,7 @@ def test_valid_login_with_allowed_external_redirect(self):
8090
{'auth-username': '[email protected]',
8191
'auth-password': 'secret',
8292
'login_view-current_step': 'auth'})
83-
self.assertEqual(self.client.session.get('next'), redirect_url)
84-
self.assertRedirects(response, reverse('two_factor:setup'), fetch_redirect_response=False)
93+
self.assertRedirects(response, redirect_url, fetch_redirect_response=False)
8594

8695
def test_valid_login_with_disallowed_external_redirect(self):
8796
redirect_url = 'https://test.disallowed-success-url.com'
@@ -91,7 +100,7 @@ def test_valid_login_with_disallowed_external_redirect(self):
91100
{'auth-username': '[email protected]',
92101
'auth-password': 'secret',
93102
'login_view-current_step': 'auth'})
94-
self.assertRedirects(response, reverse('two_factor:setup'), fetch_redirect_response=False)
103+
self.assertRedirects(response, reverse('two_factor:profile'), fetch_redirect_response=False)
95104

96105
@mock.patch('two_factor.views.core.time')
97106
def test_valid_login_primary_key_stored(self, mock_time):
@@ -396,12 +405,12 @@ def test_login_different_user_on_existing_session(self, mock_logger):
396405
response = self._post({'auth-username': '[email protected]',
397406
'auth-password': 'secret',
398407
'login_view-current_step': 'auth'})
399-
self.assertRedirects(response, reverse('two_factor:setup'))
408+
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
400409

401410
response = self._post({'auth-username': '[email protected]',
402411
'auth-password': 'secret',
403412
'login_view-current_step': 'auth'})
404-
self.assertRedirects(response, reverse('two_factor:setup'))
413+
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
405414

406415
def test_missing_management_data(self):
407416
# missing management data
@@ -432,7 +441,7 @@ def test_login_different_user_with_otp_on_existing_session(self):
432441
response = self._post({'auth-username': '[email protected]',
433442
'auth-password': 'secret',
434443
'login_view-current_step': 'auth'})
435-
self.assertRedirects(response, reverse('two_factor:setup'))
444+
self.assertRedirects(response, resolve_url(settings.LOGIN_REDIRECT_URL))
436445

437446
response = self._post({'auth-username': '[email protected]',
438447
'auth-password': 'secret',

tests/urls.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from two_factor.urls import urlpatterns as tf_urls
66
from two_factor.views import LoginView
77

8-
from .views import SecureView
8+
from .views import SecureView, plain_view
99

1010
urlpatterns = [
1111
path(
@@ -38,6 +38,11 @@
3838
name='custom-redirect-authenticated-user-login',
3939
),
4040

41+
path(
42+
'plain/',
43+
plain_view,
44+
name="plain",
45+
),
4146
path(
4247
'secure/',
4348
SecureView.as_view(),

tests/views.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
from django.http import HttpResponse
12
from django.views.generic import TemplateView
23

34
from two_factor.views import OTPRequiredMixin
45

56

67
class SecureView(OTPRequiredMixin, TemplateView):
78
template_name = 'secure.html'
9+
10+
11+
def plain_view(request):
12+
""" Non-class based view """
13+
return HttpResponse('plain')

two_factor/views/core.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from two_factor.plugins.phonenumber.utils import get_available_phone_methods
3939
from two_factor.plugins.registry import registry
4040
from two_factor.utils import totp_digits
41+
from two_factor.views.mixins import OTPRequiredMixin
4142

4243
from ..forms import (
4344
AuthenticationTokenForm, BackupTokenForm, DeviceValidationForm, MethodForm,
@@ -174,16 +175,17 @@ def done(self, form_list, **kwargs):
174175
httponly=getattr(settings, 'TWO_FACTOR_REMEMBER_COOKIE_HTTPONLY', True),
175176
samesite=getattr(settings, 'TWO_FACTOR_REMEMBER_COOKIE_SAMESITE', 'Lax'),
176177
)
177-
178178
return response
179179

180180
# If the user does not have a device.
181-
else:
181+
elif OTPRequiredMixin.is_otp_view(self.request.GET.get('next')):
182182
if self.request.GET.get('next'):
183183
self.request.session['next'] = self.get_success_url()
184184
return redirect('two_factor:setup')
185185

186-
# Copied from django.contrib.auth.views.LoginView (Branch: stable/1.11.x)
186+
return response
187+
188+
# Copied from django.conrib.auth.views.LoginView (Branch: stable/1.11.x)
187189
# https://github.com/django/django/blob/58df8aa40fe88f753ba79e091a52f236246260b3/django/contrib/auth/views.py#L63
188190
def get_success_url(self):
189191
url = self.get_redirect_url()

two_factor/views/mixins.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from django.contrib.auth.views import redirect_to_login
33
from django.core.exceptions import PermissionDenied
44
from django.template.response import TemplateResponse
5-
from django.urls import reverse
5+
from django.urls import Resolver404, resolve, reverse
66

77
from ..utils import default_device
88

@@ -80,3 +80,14 @@ def dispatch(self, request, *args, **kwargs):
8080
status=403,
8181
)
8282
return super().dispatch(request, *args, **kwargs)
83+
84+
@classmethod
85+
def is_otp_view(cls, view_path):
86+
try:
87+
next_resolver_match = resolve(view_path)
88+
except Resolver404:
89+
return False
90+
return (
91+
hasattr(next_resolver_match.func, 'view_class') and
92+
issubclass(next_resolver_match.func.view_class, OTPRequiredMixin)
93+
)

0 commit comments

Comments
 (0)