Skip to content

Commit

Permalink
rollback 8f65bff, add support for ModelBackend.user_can_authenticate
Browse files Browse the repository at this point in the history
  • Loading branch information
tomwojcik committed May 3, 2024
1 parent 610c78c commit d33c399
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 24 deletions.
10 changes: 3 additions & 7 deletions djoser/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,13 @@ def __init__(self, *args, **kwargs):

def validate(self, attrs):
password = attrs.get("password")
params = {settings.LOGIN_FIELD: attrs.get(settings.LOGIN_FIELD)}
params = {"username": attrs.get(settings.LOGIN_FIELD)}
self.user = authenticate(
request=self.context.get("request"), **params, password=password
)
if not self.user:
self.user = User.objects.filter(**params).first()
if self.user and not self.user.check_password(password):
self.fail("invalid_credentials")
if self.user and self.user.is_active:
return attrs
self.fail("invalid_credentials")
self.fail("invalid_credentials")
return attrs


class UserFunctionsMixin:
Expand Down
234 changes: 217 additions & 17 deletions testproject/testapp/tests/test_token_create.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import django
from unittest import mock

from django.conf import settings as django_settings
from django.contrib.auth import user_logged_in, user_login_failed
from django.contrib.auth.backends import ModelBackend
from django.test import override_settings
from djet import assertions
from rest_framework import status
Expand Down Expand Up @@ -37,9 +40,221 @@ def test_post_should_login_user(self):
self.assertNotEqual(user.last_login, previous_last_login)
self.assertTrue(self.signal_sent)

@override_settings(
AUTHENTICATION_BACKENDS=[
"django.contrib.auth.backends.ModelBackend",
]
)
@override_settings(
DJOSER=dict(django_settings.DJOSER, **{"LOGIN_FIELD": "username"})
)
def test_post_should_not_login_if_model_backend_user_can_authenticate__LOGIN_FIELD_username__USERNAME_FIELD_username( # noqa: E501
self,
):
user = create_user()
user_logged_in.connect(self.signal_receiver)
previous_last_login = user.last_login

with mock.patch("djoser.serializers.User.USERNAME_FIELD", "username"):
with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_200_OK)

user.refresh_from_db()
self.assertEqual(response.data["auth_token"], user.auth_token.key)
self.assertNotEqual(user.last_login, previous_last_login)
self.assertTrue(self.signal_sent)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

@override_settings(
AUTHENTICATION_BACKENDS=[
"django.contrib.auth.backends.ModelBackend",
]
)
@override_settings(DJOSER=dict(django_settings.DJOSER, **{"LOGIN_FIELD": "email"}))
def test_post_should_not_login_if_model_backend_user_can_authenticate__LOGIN_FIELD_email__USERNAME_FIELD_username( # noqa: E501
self,
):
user = create_user()
user_logged_in.connect(self.signal_receiver)
previous_last_login = user.last_login

with mock.patch("djoser.serializers.User.USERNAME_FIELD", "username"):
with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

user.refresh_from_db()
self.assertEqual(user.last_login, previous_last_login)
self.assertFalse(self.signal_sent)

@override_settings(
AUTHENTICATION_BACKENDS=[
"django.contrib.auth.backends.ModelBackend",
]
)
@override_settings(
DJOSER=dict(django_settings.DJOSER, **{"LOGIN_FIELD": "username"})
)
def test_post_should_not_login_if_model_backend_user_can_authenticate__LOGIN_FIELD_username__USERNAME_FIELD_email( # noqa: E501
self,
):
user = create_user()
user_logged_in.connect(self.signal_receiver)
previous_last_login = user.last_login

with mock.patch("djoser.serializers.User.USERNAME_FIELD", "email"):
with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

user.refresh_from_db()
self.assertEqual(user.last_login, previous_last_login)
self.assertFalse(self.signal_sent)

@override_settings(
AUTHENTICATION_BACKENDS=[
"django.contrib.auth.backends.ModelBackend",
]
)
@override_settings(DJOSER=dict(django_settings.DJOSER, **{"LOGIN_FIELD": "email"}))
def test_post_should_not_login_if_model_backend_user_can_authenticate__LOGIN_FIELD_email__USERNAME_FIELD_email( # noqa: E501
self,
):
user = create_user()
user_logged_in.connect(self.signal_receiver)
previous_last_login = user.last_login

with mock.patch("djoser.serializers.User.USERNAME_FIELD", "email"):
with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url,
{"username": user.username, "password": user.raw_password},
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=True
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_200_OK)

user.refresh_from_db()
self.assertEqual(response.data["auth_token"], user.auth_token.key)
self.assertNotEqual(user.last_login, previous_last_login)
self.assertTrue(self.signal_sent)

with mock.patch.object(
ModelBackend, "user_can_authenticate", return_value=False
):
response = self.client.post(
self.base_url, {"email": user.email, "password": user.raw_password}
)
self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)

def test_post_should_not_login_if_user_is_not_active(self):
"""In Django >= 1.10 authenticate() returns None if user is inactive,
while in Django < 1.10 authenticate() succeeds if user is inactive."""
user = create_user()
data = {"username": user.username, "password": user.raw_password}
user.is_active = False
Expand Down Expand Up @@ -81,18 +296,3 @@ def test_post_should_not_login_if_empty_request(self):
response.data["non_field_errors"],
[settings.CONSTANTS.messages.INVALID_CREDENTIALS_ERROR],
)

@override_settings(DJOSER=dict(django_settings.DJOSER, **{"LOGIN_FIELD": "email"}))
def test_login_using_email(self):
user = create_user()
previous_last_login = user.last_login
data = {"email": user.email, "password": user.raw_password}
user_logged_in.connect(self.signal_receiver)

response = self.client.post(self.base_url, data)
user.refresh_from_db()

self.assert_status_equal(response, status.HTTP_200_OK)
self.assertEqual(response.data["auth_token"], user.auth_token.key)
self.assertNotEqual(user.last_login, previous_last_login)
self.assertTrue(self.signal_sent)

0 comments on commit d33c399

Please sign in to comment.