diff options
Diffstat (limited to 'django/contrib/auth/forms.py')
-rw-r--r-- | django/contrib/auth/forms.py | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 02250d83da..3741fdea7c 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -16,12 +16,27 @@ from django.core.mail import EmailMultiAlternatives from django.template import loader from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode +from django.utils.six import PY3 from django.utils.text import capfirst from django.utils.translation import ugettext, ugettext_lazy as _ UserModel = get_user_model() +def _unicode_ci_compare(s1, s2): + """ + Perform case-insensitive comparison of two identifiers, using the + recommended algorithm from Unicode Technical Report 36, section + 2.11.2(B)(2). + """ + normalized1 = unicodedata.normalize('NFKC', s1) + normalized2 = unicodedata.normalize('NFKC', s2) + if PY3: + return normalized1.casefold() == normalized2.casefold() + # lower() is the best alternative available on Python 2. + return normalized1.lower() == normalized2.lower() + + class ReadOnlyPasswordHashWidget(forms.Widget): template_name = 'auth/widgets/read_only_password_hash.html' @@ -249,11 +264,16 @@ class PasswordResetForm(forms.Form): that prevent inactive users and users with unusable passwords from resetting their password. """ + email_field_name = UserModel.get_email_field_name() active_users = UserModel._default_manager.filter(**{ - '%s__iexact' % UserModel.get_email_field_name(): email, + '%s__iexact' % email_field_name: email, 'is_active': True, }) - return (u for u in active_users if u.has_usable_password()) + return ( + u for u in active_users + if u.has_usable_password() and + _unicode_ci_compare(email, getattr(u, email_field_name)) + ) def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', @@ -266,6 +286,7 @@ class PasswordResetForm(forms.Form): user. """ email = self.cleaned_data["email"] + email_field_name = UserModel.get_email_field_name() for user in self.get_users(email): if not domain_override: current_site = get_current_site(request) @@ -273,8 +294,9 @@ class PasswordResetForm(forms.Form): domain = current_site.domain else: site_name = domain = domain_override + user_email = getattr(user, email_field_name) context = { - 'email': email, + 'email': user_email, 'domain': domain, 'site_name': site_name, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), @@ -286,7 +308,7 @@ class PasswordResetForm(forms.Form): context.update(extra_email_context) self.send_mail( subject_template_name, email_template_name, context, from_email, - email, html_email_template_name=html_email_template_name, + user_email, html_email_template_name=html_email_template_name, ) |