diff --git a/django/contrib/auth/urls.py b/django/contrib/auth/urls.py index 233eef8..d4e5d4b 100644 --- a/django/contrib/auth/urls.py +++ b/django/contrib/auth/urls.py @@ -15,6 +15,8 @@ urlpatterns = [ url(r'^password_reset/$', views.PasswordResetView.as_view(), name='password_reset'), url(r'^password_reset/done/$', views.PasswordResetDoneView.as_view(), name='password_reset_done'), + url(r'^reset/(?P[0-9A-Za-z_\-]+)/$', + views.password_reset_confirm_secure, name='password_reset_confirm_secure'), url(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), url(r'^reset/done/$', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'), diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index b84fae8..2117af2 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -14,7 +14,7 @@ from django.contrib.auth.forms import ( from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.shortcuts import get_current_site from django.http import HttpResponseRedirect, QueryDict -from django.shortcuts import resolve_url +from django.shortcuts import resolve_url, redirect from django.template.response import TemplateResponse from django.urls import reverse, reverse_lazy from django.utils.decorators import method_decorator @@ -314,13 +314,49 @@ def password_reset_confirm(request, uidb64=None, token=None, post_reset_redirect=None, extra_context=None): """ + Redirect to the real password reset view to not contain anymore the token in + the url. + """ + assert uidb64 is not None and token is not None # checked by URLconf + request.session['internal-reset-token'] = token + request.session['password_reset_parameters'] = dict( + template_name=template_name, + token_generator=token_generator, + set_password_form=set_password_form, + post_reset_redirect=post_reset_redirect, + extra_context=extra_context, + ) + return redirect('password_reset_confirm_secure', uidb64=uidb64) + + +# Doesn't need csrf_protect since no-one can guess the URL +@sensitive_post_parameters() +@never_cache +@deprecate_current_app +def password_reset_confirm_secure(request, uidb64=None, + template_name='registration/password_reset_confirm.html', + token_generator=default_token_generator, + set_password_form=SetPasswordForm, + post_reset_redirect=None, + extra_context=None): + """ View that checks the hash in a password reset link and presents a form for entering a new password. """ warnings.warn("The password_reset_confirm() view is superseded by the " "class-based PasswordResetConfirmView().", RemovedInDjango21Warning, stacklevel=2) + + password_reset_parameters = request.session.get('password_reset_parameters') + if password_reset_parameters: + template_name = password_reset_parameters['template_name'] + token_generator = password_reset_parameters['token_generator'] + set_password_form = password_reset_parameters['set_password_form'] + post_reset_redirect = password_reset_parameters['post_reset_redirect'] + extra_context = password_reset_parameters['extra_context'] + UserModel = get_user_model() + token = request.session.get('internal-reset-token') assert uidb64 is not None and token is not None # checked by URLconf if post_reset_redirect is None: post_reset_redirect = reverse('password_reset_complete') @@ -344,6 +380,7 @@ def password_reset_confirm(request, uidb64=None, token=None, else: form = set_password_form(user) else: + del request.session['internal-reset-token'] validlink = False form = None title = _('Password reset unsuccessful')