summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2019-12-16 21:51:57 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-12-18 09:11:39 +0100
commit5b1fbcef7a8bec991ebe7b2a18b5d5a95d72cb70 (patch)
tree77991a30e32bb8f18971a89f23461b66714931fe /django
parentf4647179ccd13c852563205273163b641d4b01a5 (diff)
Fixed CVE-2019-19844 -- Used verified user email for password reset requests.
Co-Authored-By: Florian Apolloner <florian@apolloner.eu>
Diffstat (limited to 'django')
-rw-r--r--django/contrib/auth/forms.py24
1 files changed, 20 insertions, 4 deletions
diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index 54e85d5a33..e5e6a86c1e 100644
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -20,6 +20,15 @@ from django.utils.translation import gettext, gettext_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).
+ """
+ return unicodedata.normalize('NFKC', s1).casefold() == unicodedata.normalize('NFKC', s2).casefold()
+
+
class ReadOnlyPasswordHashWidget(forms.Widget):
template_name = 'auth/widgets/read_only_password_hash.html'
read_only = True
@@ -269,11 +278,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',
@@ -292,9 +306,11 @@ class PasswordResetForm(forms.Form):
domain = current_site.domain
else:
site_name = domain = domain_override
+ email_field_name = UserModel.get_email_field_name()
for user in self.get_users(email):
+ 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)),
@@ -305,7 +321,7 @@ class PasswordResetForm(forms.Form):
}
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,
)