From 77d455ae73b177a32102f0b248828b5d63c0aa24 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 10 Aug 2024 16:57:29 +0200 Subject: [PATCH] Standardized how method_decorator is used in contrib.auth views and admin. Updated django.contrib.auth's views and admin modules to apply decorators consistently. --- django/contrib/auth/admin.py | 8 ++------ django/contrib/auth/views.py | 40 ++++++++++++------------------------ 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index 068e8df422..89d08d3833 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -21,9 +21,6 @@ from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_protect from django.views.decorators.debug import sensitive_post_parameters -csrf_protect_m = method_decorator(csrf_protect) -sensitive_post_parameters_m = method_decorator(sensitive_post_parameters()) - @admin.register(Group) class GroupAdmin(admin.ModelAdmin): @@ -113,8 +110,7 @@ class UserAdmin(admin.ModelAdmin): lookup, value, request ) - @sensitive_post_parameters_m - @csrf_protect_m + @method_decorator([sensitive_post_parameters(), csrf_protect]) def add_view(self, request, form_url="", extra_context=None): if request.method in ("GET", "HEAD", "OPTIONS", "TRACE"): return self._add_view(request, form_url, extra_context) @@ -150,7 +146,7 @@ class UserAdmin(admin.ModelAdmin): extra_context.update(defaults) return super().add_view(request, form_url, extra_context) - @sensitive_post_parameters_m + @method_decorator(sensitive_post_parameters()) def user_change_password(self, request, id, form_url=""): user = self.get_object(request, unquote(id)) if not self.has_change_permission(request, user): diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index cd810a1edc..295f2219cf 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -62,7 +62,10 @@ class RedirectURLMixin: raise ImproperlyConfigured("No URL to redirect to. Provide a next_page.") -@method_decorator(login_not_required, name="dispatch") +@method_decorator( + [login_not_required, sensitive_post_parameters(), csrf_protect, never_cache], + name="dispatch", +) class LoginView(RedirectURLMixin, FormView): """ Display the login form and handle the login action. @@ -74,9 +77,6 @@ class LoginView(RedirectURLMixin, FormView): redirect_authenticated_user = False extra_context = None - @method_decorator(sensitive_post_parameters()) - @method_decorator(csrf_protect) - @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): if self.redirect_authenticated_user and self.request.user.is_authenticated: redirect_to = self.get_success_url() @@ -122,6 +122,7 @@ class LoginView(RedirectURLMixin, FormView): return context +@method_decorator([csrf_protect, never_cache], name="dispatch") class LogoutView(RedirectURLMixin, TemplateView): """ Log out the user and display the 'You are logged out' message. @@ -131,11 +132,6 @@ class LogoutView(RedirectURLMixin, TemplateView): template_name = "registration/logged_out.html" extra_context = None - @method_decorator(csrf_protect) - @method_decorator(never_cache) - def dispatch(self, request, *args, **kwargs): - return super().dispatch(request, *args, **kwargs) - def post(self, request, *args, **kwargs): """Logout may be done via POST.""" auth_logout(request) @@ -211,7 +207,7 @@ class PasswordContextMixin: return context -@method_decorator(login_not_required, name="dispatch") +@method_decorator([login_not_required, csrf_protect], name="dispatch") class PasswordResetView(PasswordContextMixin, FormView): email_template_name = "registration/password_reset_email.html" extra_email_context = None @@ -224,10 +220,6 @@ class PasswordResetView(PasswordContextMixin, FormView): title = _("Password reset") token_generator = default_token_generator - @method_decorator(csrf_protect) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs) - def form_valid(self, form): opts = { "use_https": self.request.is_secure(), @@ -252,7 +244,9 @@ class PasswordResetDoneView(PasswordContextMixin, TemplateView): title = _("Password reset sent") -@method_decorator(login_not_required, name="dispatch") +@method_decorator( + [login_not_required, sensitive_post_parameters(), never_cache], name="dispatch" +) class PasswordResetConfirmView(PasswordContextMixin, FormView): form_class = SetPasswordForm post_reset_login = False @@ -263,8 +257,6 @@ class PasswordResetConfirmView(PasswordContextMixin, FormView): title = _("Enter new password") token_generator = default_token_generator - @method_decorator(sensitive_post_parameters()) - @method_decorator(never_cache) def dispatch(self, *args, **kwargs): if "uidb64" not in kwargs or "token" not in kwargs: raise ImproperlyConfigured( @@ -351,18 +343,15 @@ class PasswordResetCompleteView(PasswordContextMixin, TemplateView): return context +@method_decorator( + [sensitive_post_parameters(), csrf_protect, login_required], name="dispatch" +) class PasswordChangeView(PasswordContextMixin, FormView): form_class = PasswordChangeForm success_url = reverse_lazy("password_change_done") template_name = "registration/password_change_form.html" title = _("Password change") - @method_decorator(sensitive_post_parameters()) - @method_decorator(csrf_protect) - @method_decorator(login_required) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs) - def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["user"] = self.request.user @@ -376,10 +365,7 @@ class PasswordChangeView(PasswordContextMixin, FormView): return super().form_valid(form) +@method_decorator(login_required, name="dispatch") class PasswordChangeDoneView(PasswordContextMixin, TemplateView): template_name = "registration/password_change_done.html" title = _("Password change successful") - - @method_decorator(login_required) - def dispatch(self, *args, **kwargs): - return super().dispatch(*args, **kwargs)