+83
-2
lines changedFilter options
+83
-2
lines changed Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
1
+
import logging
1
2
import unicodedata
2
3
3
4
from django import forms
@@ -16,6 +17,7 @@
16
17
from django.utils.translation import gettext_lazy as _
17
18
18
19
UserModel = get_user_model()
20
+
logger = logging.getLogger("django.contrib.auth")
19
21
20
22
21
23
def _unicode_ci_compare(s1, s2):
@@ -418,7 +420,12 @@ def send_mail(
418
420
html_email = loader.render_to_string(html_email_template_name, context)
419
421
email_message.attach_alternative(html_email, "text/html")
420
422
421
-
email_message.send()
423
+
try:
424
+
email_message.send()
425
+
except Exception:
426
+
logger.exception(
427
+
"Failed to send password reset email to %s", context["user"].pk
428
+
)
422
429
423
430
def get_users(self, email):
424
431
"""Given an email, return matching user(s) who should receive a reset.
Original file line number Diff line number Diff line change
@@ -209,6 +209,18 @@ Django development server. This logger generates an ``INFO`` message upon
209
209
detecting a modification in a source code file and may produce ``WARNING``
210
210
messages during filesystem inspection and event subscription processes.
211
211
212
+
.. _django-contrib-auth-logger:
213
+
214
+
``django.contrib.auth``
215
+
~~~~~~~~~~~~~~~~~~~~~~~
216
+
217
+
.. versionadded:: 4.2.16
218
+
219
+
Log messages related to :doc:`contrib/auth`, particularly ``ERROR`` messages
220
+
are generated when a :class:`~django.contrib.auth.forms.PasswordResetForm` is
221
+
successfully submitted but the password reset email cannot be delivered due to
222
+
a mail sending exception.
223
+
212
224
.. _django-contrib-gis-logger:
213
225
214
226
``django.contrib.gis``
Original file line number Diff line number Diff line change
@@ -13,3 +13,14 @@ CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html
13
13
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
14
14
denial-of-service attack via very large inputs with a specific sequence of
15
15
characters.
16
+
17
+
CVE-2024-45231: Potential user email enumeration via response status on password reset
18
+
======================================================================================
19
+
20
+
Due to unhandled email sending failures, the
21
+
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
22
+
attackers to enumerate user emails by issuing password reset requests and
23
+
observing the outcomes.
24
+
25
+
To mitigate this risk, exceptions occurring during password reset email sending
26
+
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
Original file line number Diff line number Diff line change
@@ -13,3 +13,14 @@ CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html
13
13
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
14
14
denial-of-service attack via very large inputs with a specific sequence of
15
15
characters.
16
+
17
+
CVE-2024-45231: Potential user email enumeration via response status on password reset
18
+
======================================================================================
19
+
20
+
Due to unhandled email sending failures, the
21
+
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
22
+
attackers to enumerate user emails by issuing password reset requests and
23
+
observing the outcomes.
24
+
25
+
To mitigate this risk, exceptions occurring during password reset email sending
26
+
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
Original file line number Diff line number Diff line change
@@ -14,6 +14,17 @@ CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html
14
14
denial-of-service attack via very large inputs with a specific sequence of
15
15
characters.
16
16
17
+
CVE-2024-45231: Potential user email enumeration via response status on password reset
18
+
======================================================================================
19
+
20
+
Due to unhandled email sending failures, the
21
+
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
22
+
attackers to enumerate user emails by issuing password reset requests and
23
+
observing the outcomes.
24
+
25
+
To mitigate this risk, exceptions occurring during password reset email sending
26
+
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
27
+
17
28
Bugfixes
18
29
========
19
30
Original file line number Diff line number Diff line change
@@ -1752,7 +1752,9 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
1752
1752
.. method:: send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)
1753
1753
1754
1754
Uses the arguments to send an ``EmailMultiAlternatives``.
1755
-
Can be overridden to customize how the email is sent to the user.
1755
+
Can be overridden to customize how the email is sent to the user. If
1756
+
you choose to override this method, be mindful of handling potential
1757
+
exceptions raised due to email sending failures.
1756
1758
1757
1759
:param subject_template_name: the template for the subject.
1758
1760
:param email_template_name: the template for the email body.
Original file line number Diff line number Diff line change
@@ -1351,6 +1351,27 @@ def test_save_html_email_template_name(self):
1351
1351
)
1352
1352
)
1353
1353
1354
+
@override_settings(EMAIL_BACKEND="mail.custombackend.FailingEmailBackend")
1355
+
def test_save_send_email_exceptions_are_catched_and_logged(self):
1356
+
(user, username, email) = self.create_dummy_user()
1357
+
form = PasswordResetForm({"email": email})
1358
+
self.assertTrue(form.is_valid())
1359
+
1360
+
with self.assertLogs("django.contrib.auth", level=0) as cm:
1361
+
form.save()
1362
+
1363
+
self.assertEqual(len(mail.outbox), 0)
1364
+
self.assertEqual(len(cm.output), 1)
1365
+
errors = cm.output[0].split("\n")
1366
+
pk = user.pk
1367
+
self.assertEqual(
1368
+
errors[0],
1369
+
f"ERROR:django.contrib.auth:Failed to send password reset email to {pk}",
1370
+
)
1371
+
self.assertEqual(
1372
+
errors[-1], "ValueError: FailingEmailBackend is doomed to fail."
1373
+
)
1374
+
1354
1375
@override_settings(AUTH_USER_MODEL="auth_tests.CustomEmailField")
1355
1376
def test_custom_email_field(self):
1356
1377
email = "test@mail.com"
Original file line number Diff line number Diff line change
@@ -12,3 +12,9 @@ def send_messages(self, email_messages):
12
12
# Messages are stored in an instance variable for testing.
13
13
self.test_outbox.extend(email_messages)
14
14
return len(email_messages)
15
+
16
+
17
+
class FailingEmailBackend(BaseEmailBackend):
18
+
19
+
def send_messages(self, email_messages):
20
+
raise ValueError("FailingEmailBackend is doomed to fail.")
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4