Refactored out RedirectURLMixin.get_redirect_url().

This also renames SuccessURLAllowedHostsMixin to RedirectURLMixin.

This doesn't change the behavior of LogoutView.get_next_page() because
next_page == "" implies url_is_safe == False before the refactoring.
This commit is contained in:
Aymeric Augustin 2022-04-16 18:37:34 +02:00 committed by Mariusz Felisiak
parent 420d13edee
commit 12576bd371
2 changed files with 21 additions and 28 deletions

View File

@ -34,14 +34,27 @@ from django.views.generic.edit import FormView
UserModel = get_user_model() UserModel = get_user_model()
class SuccessURLAllowedHostsMixin: class RedirectURLMixin:
redirect_field_name = REDIRECT_FIELD_NAME
success_url_allowed_hosts = set() success_url_allowed_hosts = set()
def get_redirect_url(self):
"""Return the user-originating redirect URL if it's safe."""
redirect_to = self.request.POST.get(
self.redirect_field_name, self.request.GET.get(self.redirect_field_name)
)
url_is_safe = url_has_allowed_host_and_scheme(
url=redirect_to,
allowed_hosts=self.get_success_url_allowed_hosts(),
require_https=self.request.is_secure(),
)
return redirect_to if url_is_safe else ""
def get_success_url_allowed_hosts(self): def get_success_url_allowed_hosts(self):
return {self.request.get_host(), *self.success_url_allowed_hosts} return {self.request.get_host(), *self.success_url_allowed_hosts}
class LoginView(SuccessURLAllowedHostsMixin, FormView): class LoginView(RedirectURLMixin, FormView):
""" """
Display the login form and handle the login action. Display the login form and handle the login action.
""" """
@ -49,7 +62,6 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
form_class = AuthenticationForm form_class = AuthenticationForm
authentication_form = None authentication_form = None
next_page = None next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = "registration/login.html" template_name = "registration/login.html"
redirect_authenticated_user = False redirect_authenticated_user = False
extra_context = None extra_context = None
@ -71,18 +83,6 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
def get_success_url(self): def get_success_url(self):
return self.get_redirect_url() or self.get_default_redirect_url() return self.get_redirect_url() or self.get_default_redirect_url()
def get_redirect_url(self):
"""Return the user-originating redirect URL if it's safe."""
redirect_to = self.request.POST.get(
self.redirect_field_name, self.request.GET.get(self.redirect_field_name)
)
url_is_safe = url_has_allowed_host_and_scheme(
url=redirect_to,
allowed_hosts=self.get_success_url_allowed_hosts(),
require_https=self.request.is_secure(),
)
return redirect_to if url_is_safe else ""
def get_default_redirect_url(self): def get_default_redirect_url(self):
"""Return the default redirect URL.""" """Return the default redirect URL."""
return resolve_url(self.next_page or settings.LOGIN_REDIRECT_URL) return resolve_url(self.next_page or settings.LOGIN_REDIRECT_URL)
@ -114,7 +114,7 @@ class LoginView(SuccessURLAllowedHostsMixin, FormView):
return context return context
class LogoutView(SuccessURLAllowedHostsMixin, TemplateView): class LogoutView(RedirectURLMixin, TemplateView):
""" """
Log out the user and display the 'You are logged out' message. Log out the user and display the 'You are logged out' message.
""" """
@ -123,7 +123,6 @@ class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
# "head" from http_method_names. # "head" from http_method_names.
http_method_names = ["get", "head", "post", "options"] http_method_names = ["get", "head", "post", "options"]
next_page = None next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = "registration/logged_out.html" template_name = "registration/logged_out.html"
extra_context = None extra_context = None
@ -164,17 +163,8 @@ class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
self.redirect_field_name in self.request.POST self.redirect_field_name in self.request.POST
or self.redirect_field_name in self.request.GET or self.redirect_field_name in self.request.GET
): ):
next_page = self.request.POST.get( next_page = self.get_redirect_url()
self.redirect_field_name, self.request.GET.get(self.redirect_field_name) if next_page == "":
)
url_is_safe = url_has_allowed_host_and_scheme(
url=next_page,
allowed_hosts=self.get_success_url_allowed_hosts(),
require_https=self.request.is_secure(),
)
# Security check -- Ensure the user-originating redirection URL is
# safe.
if not url_is_safe:
if settings.LOGOUT_REDIRECT_URL: if settings.LOGOUT_REDIRECT_URL:
next_page = resolve_url(settings.LOGOUT_REDIRECT_URL) next_page = resolve_url(settings.LOGOUT_REDIRECT_URL)
else: else:

View File

@ -495,6 +495,9 @@ Miscellaneous
enabled in development. You may specify ``OPTIONS['loaders']`` to override enabled in development. You may specify ``OPTIONS['loaders']`` to override
this, if necessary. this, if necessary.
* The undocumented ``django.contrib.auth.views.SuccessURLAllowedHostsMixin``
mixin is replaced by ``RedirectURLMixin``.
.. _deprecated-features-4.1: .. _deprecated-features-4.1:
Features deprecated in 4.1 Features deprecated in 4.1