Commit 32ce8428 authored by okhin's avatar okhin 🚴

Fixing the auth backend to allow username or email validation

parent 2c0989b3
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
class EmailOrUsernameModelBackend(ModelBackend):
"""
Authentification backend to allow email
overide AUTHENTICATION_BACKENDS with
fabauth.auth_backends.EmailOrUsernameModelBackend
We allow for email or username to be used as a login.
Case insensitive.
"""
def authenticate(self, username=None, password=None, **kwargs):
if "@" in username:
kwargs = {"email": username}
else:
kwargs = {"username": username}
def authenticate(self, request, username=None, password=None):
# If we call this function, it means we're not authenticated yet.
# Since we're going through the classic Model backend first, it means
# that the user does not exists.
UserModel = get_user_model()
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
user = UserModel.objects.get(email=username)
if user.check_password(raw_password=password):
return user
except User.DoesNotExist:
except UserModel.DoesNotExist:
# The User does not exist. Hashing the password anyway,
# to limit Time attacks efficiency
UserModel().set_password(raw_password=password)
return None
def get_user(self, user_id):
# This is used to get the User objects
UserModel = get_user_model()
print("get_user: {}".format(user_id))
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
from django.test import TestCase
from django.test import Client
from django.test import Client, override_settings
from django_factory_boy import auth as auth_factories
AUTHENTICATION_BACKENDS = [
@override_settings(AUTHENTICATION_BACKENDS=[
# Default
"django.contrib.auth.backends.ModelBackend",
# Email or Username for login
"core.auth_backends.EmailOrUsernameModelBackend"
]
])
class ApiTest(TestCase):
def setUp(self):
self.client = Client()
self.user = auth_factories.UserFactory(password="dummypassword")
def test_authenticate(self):
with self.settings(AUTHENTICATION_BACKENDS=AUTHENTICATION_BACKENDS):
# username, wrong password
login_status = self.client.login(
username=self.user.username,
password="notthepassword"
)
assert not login_status
# username, correct password
login_status = self.client.login(
username=self.user.username,
password="dummypassword"
)
assert login_status
# email, wrong password
login_status = self.client.login(
username=self.user.email,
password="notthepassowrd"
)
assert not login_status
# email, correct password
login_status = self.client.login(
username=self.user.email,
password="dummypassword"
)
assert login_status
# username, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.username),
password="dummypassword"
)
assert not login_status
# email, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.email),
password="dummypassword"
)
assert not login_status
# username, wrong password
login_status = self.client.login(
username=self.user.username,
password="notthepassword"
)
assert not login_status
# username, correct password
login_status = self.client.login(
username=self.user.username,
password="dummypassword"
)
assert login_status
# email, wrong password
login_status = self.client.login(
username=self.user.email,
password="notthepassowrd"
)
assert not login_status
# email, correct password
login_status = self.client.login(
username=self.user.email,
password="dummypassword"
)
assert login_status
# username, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.username),
password="dummypassword"
)
assert not login_status
# email, wrong user
login_status = self.client.login(
username="{}-2".format(self.user.email),
password="dummypassword"
)
assert not login_status
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment