Skip to content

Commit 5da15aa

Browse files
authored
Merge pull request #152 from pascalski/master
Adding unicode check regarding CVE-2019-19844
2 parents a5262f3 + 789a542 commit 5da15aa

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

django_rest_passwordreset/views.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import unicodedata
12
from datetime import timedelta
23

34
from django.conf import settings
@@ -34,6 +35,18 @@
3435
HTTP_IP_ADDRESS_HEADER = getattr(settings, 'DJANGO_REST_PASSWORDRESET_IP_ADDRESS_HEADER', 'REMOTE_ADDR')
3536

3637

38+
def _unicode_ci_compare(s1, s2):
39+
"""
40+
Perform case-insensitive comparison of two identifiers, using the
41+
recommended algorithm from Unicode Technical Report 36, section
42+
2.11.2(B)(2).
43+
"""
44+
normalized1 = unicodedata.normalize('NFKC', s1)
45+
normalized2 = unicodedata.normalize('NFKC', s2)
46+
47+
return normalized1.casefold() == normalized2.casefold()
48+
49+
3750
class ResetPasswordValidateToken(GenericAPIView):
3851
"""
3952
An Api View which provides a method to verify that a token is valid
@@ -139,7 +152,8 @@ def post(self, request, *args, **kwargs):
139152
# last but not least: iterate over all users that are active and can change their password
140153
# and create a Reset Password Token and send a signal with the created token
141154
for user in users:
142-
if user.eligible_for_reset():
155+
if user.eligible_for_reset() and \
156+
_unicode_ci_compare(email, getattr(user, get_password_reset_lookup_field())):
143157
# define the token as none for now
144158
token = None
145159

tests/test/test_auth_test_case.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def setUp(self):
2020
self.user2 = User.objects.create_user("user2", "[email protected]", "secret2")
2121
self.user3 = User.objects.create_user("[email protected]", "[email protected]", "secret3")
2222
self.user4 = User.objects.create_user("user4", "[email protected]")
23+
self.user5 = User.objects.create_user("user5", "uѕ[email protected]", "secret5") # email contains kyrillic s
2324

2425
def test_try_reset_password_email_does_not_exist(self):
2526
""" Tests requesting a token for an email that does not exist """
@@ -29,6 +30,13 @@ def test_try_reset_password_email_does_not_exist(self):
2930
# response should have "email" in it
3031
self.assertTrue("email" in decoded_response)
3132

33+
def test_unicode_email_reset(self):
34+
response = self.rest_do_request_reset_token(email="uѕ[email protected]")
35+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
36+
37+
decoded_response = json.loads(response.content.decode())
38+
self.assertEqual(decoded_response.get("email")[0], 'Enter a valid email address.')
39+
3240
@patch('django_rest_passwordreset.signals.reset_password_token_created.send')
3341
def test_validate_token(self, mock_reset_password_token_created):
3442
""" Tests validate token """

0 commit comments

Comments
 (0)