From a42711476216b5fea22ea4bfce161db2abc442fc Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 16 Nov 2015 08:20:57 +0100 Subject: [PATCH 1/2] Enabling lowercase for username or email when allowed --- taiga/users/api.py | 10 +---- taiga/users/services.py | 26 ++++++++---- tests/integration/test_auth_api.py | 64 ++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 15 deletions(-) diff --git a/taiga/users/api.py b/taiga/users/api.py index d72d021d..20031395 100644 --- a/taiga/users/api.py +++ b/taiga/users/api.py @@ -35,7 +35,7 @@ from taiga.base.api.utils import get_object_or_404 from taiga.base.filters import MembersFilterBackend from taiga.base.mails import mail_builder from taiga.projects.votes import services as votes_service - +from taiga.users.services import get_user_by_username_or_email from easy_thumbnails.source_generators import pil_image from . import models @@ -145,13 +145,7 @@ class UsersViewSet(ModelCrudViewSet): if not username_or_email: raise exc.WrongArguments(_("Invalid username or email")) - try: - queryset = models.User.objects.all() - user = queryset.get(Q(username=username_or_email) | - Q(email=username_or_email)) - except models.User.DoesNotExist: - raise exc.WrongArguments(_("Invalid username or email")) - + user = get_user_by_username_or_email(username_or_email) user.token = str(uuid.uuid1()) user.save(update_fields=["token"]) diff --git a/taiga/users/services.py b/taiga/users/services.py index 3ef4672d..5dd8bc0f 100644 --- a/taiga/users/services.py +++ b/taiga/users/services.py @@ -37,6 +37,24 @@ from .gravatar import get_gravatar_url from django.conf import settings + +def get_user_by_username_or_email(username_or_email): + user_model = apps.get_model("users", "User") + qs = user_model.objects.filter(Q(username__iexact=username_or_email) | + Q(email__iexact=username_or_email)) + + if len(qs) > 1: + qs = qs.filter(Q(username=username_or_email) | + Q(email=username_or_email)) + + if len(qs) == 0: + raise exc.WrongArguments(_("Username or password does not matches user.")) + + user = qs[0] + return user + + + def get_and_validate_user(*, username:str, password:str) -> bool: """ Check if user with username/email exists and specified @@ -46,13 +64,7 @@ def get_and_validate_user(*, username:str, password:str) -> bool: exception is raised. """ - user_model = apps.get_model("users", "User") - qs = user_model.objects.filter(Q(username=username) | - Q(email=username)) - if len(qs) == 0: - raise exc.WrongArguments(_("Username or password does not matches user.")) - - user = qs[0] + user = get_user_by_username_or_email(username) if not user.check_password(password): raise exc.WrongArguments(_("Username or password does not matches user.")) diff --git a/tests/integration/test_auth_api.py b/tests/integration/test_auth_api.py index e7a7805a..02df17fa 100644 --- a/tests/integration/test_auth_api.py +++ b/tests/integration/test_auth_api.py @@ -106,3 +106,67 @@ def test_respond_400_if_username_or_email_is_duplicate(client, settings, registe register_form["email"] = "ff@dd.com" response = client.post(reverse("auth-register"), register_form) assert response.status_code == 400 + + +def test_auth_uppercase_ignore(client, settings): + settings.PUBLIC_REGISTER_ENABLED = True + + register_form = {"username": "Username", + "password": "password", + "full_name": "fname", + "email": "User@email.com", + "type": "public"} + response = client.post(reverse("auth-register"), register_form) + + #Only exists one user with the same lowercase version of username/password + login_form = {"type": "normal", + "username": "Username", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 200 + + login_form = {"type": "normal", + "username": "User@email.com", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 200 + + #Now we have two users with the same lowercase version of username/password + # 1.- The capitalized version works + register_form = {"username": "username", + "password": "password", + "full_name": "fname", + "email": "user@email.com", + "type": "public"} + response = client.post(reverse("auth-register"), register_form) + + login_form = {"type": "normal", + "username": "Username", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 200 + + login_form = {"type": "normal", + "username": "User@email.com", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 200 + + # 2.- If we capitalize a new version it doesn't + login_form = {"type": "normal", + "username": "uSername", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 400 + + login_form = {"type": "normal", + "username": "uSer@email.com", + "password": "password"} + + response = client.post(reverse("auth-list"), login_form) + assert response.status_code == 400 From 9d7adea9e28a18a50a92e63d2b4620490964185e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Tue, 17 Nov 2015 16:57:24 +0100 Subject: [PATCH 2/2] Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e1fc20..ab886bcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - [CSV Reports] Add fields "created_date", "modified_date", "finished_date" to issues CSV report. ### Misc +- Improve login and forgot password: allow username or email case-insensitive if the query only + match with one user. - Improve the django admin panel, now it is more usable and all the selector fields works properly. - [API] Performance improvements for project stats. - Lots of small and not so small bugfixes.