Fixed #31443 -- Fixed login redirection in auth mixins when LOGIN_URL is off-site URL.
This commit is contained in:
parent
136ec9b62b
commit
cc7c16af98
|
@ -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):
|
||||||
|
|
|
@ -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')
|
||||||
|
|
Loading…
Reference in New Issue