Fixed #31443 -- Fixed login redirection in auth mixins when LOGIN_URL is off-site URL.

This commit is contained in:
Frantisek Holop 2020-04-09 13:04:49 +02:00 committed by Mariusz Felisiak
parent 136ec9b62b
commit cc7c16af98
2 changed files with 34 additions and 1 deletions

View File

@ -1,7 +1,10 @@
from urllib.parse import urlparse
from django.conf import settings from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.views import redirect_to_login from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.shortcuts import resolve_url
class AccessMixin: class AccessMixin:
@ -41,7 +44,23 @@ class AccessMixin:
def handle_no_permission(self): def handle_no_permission(self):
if self.raise_exception or self.request.user.is_authenticated: if self.raise_exception or self.request.user.is_authenticated:
raise PermissionDenied(self.get_permission_denied_message()) raise PermissionDenied(self.get_permission_denied_message())
return redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())
path = self.request.build_absolute_uri()
resolved_login_url = resolve_url(self.get_login_url())
# If the login url is the same scheme and net location then use the
# path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if (
(not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)
):
path = self.request.get_full_path()
return redirect_to_login(
path,
resolved_login_url,
self.get_redirect_field_name(),
)
class LoginRequiredMixin(AccessMixin): class LoginRequiredMixin(AccessMixin):

View File

@ -94,6 +94,20 @@ class AccessMixinTests(TestCase):
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, '/accounts/login/?next=/rand') self.assertEqual(response.url, '/accounts/login/?next=/rand')
def test_access_mixin_permission_denied_remote_login_url(self):
class AView(AlwaysFalseView):
login_url = 'https://www.remote.example.com/login'
view = AView.as_view()
request = self.factory.get('/rand')
request.user = AnonymousUser()
response = view(request)
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.url,
'https://www.remote.example.com/login?next=http%3A//testserver/rand',
)
@mock.patch.object(models.User, 'is_authenticated', False) @mock.patch.object(models.User, 'is_authenticated', False)
def test_stacked_mixins_not_logged_in(self): def test_stacked_mixins_not_logged_in(self):
user = models.User.objects.create(username='joe', password='qwerty') user = models.User.objects.create(username='joe', password='qwerty')