From bb2fb65f7d82775122b21c65cf6797b1ff5a2505 Mon Sep 17 00:00:00 2001 From: Poderyagin Egor Date: Sun, 13 Dec 2015 23:43:33 +0300 Subject: [PATCH 1/2] Auth by email --- rest_auth/serializers.py | 13 ++++++++--- rest_auth/tests/test_api.py | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index a2d1a82..5bf1ac2 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -50,11 +50,18 @@ class LoginSerializer(serializers.Serializer): msg = _('Must include either "username" or "email" and "password".') raise exceptions.ValidationError(msg) - elif username and password: - user = authenticate(username=username, password=password) + elif username or email and password: + # Try get username if we have in request email + if email and not username: + try: + username = UserModel.objects.get(email__iexact=email).username + except UserModel.DoesNotExist: + user = None + if username: + user = authenticate(username=username, password=password) else: - msg = _('Must include "username" and "password".') + msg = _('Must include either "username" or "email" and "password".') raise exceptions.ValidationError(msg) # Did we get back an active user? diff --git a/rest_auth/tests/test_api.py b/rest_auth/tests/test_api.py index 7adcf71..8420d2d 100644 --- a/rest_auth/tests/test_api.py +++ b/rest_auth/tests/test_api.py @@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse from django.test import TestCase from django.contrib.auth import get_user_model from django.core import mail +from django.conf import settings from django.test.utils import override_settings from django.utils.encoding import force_text @@ -90,6 +91,51 @@ class APITestCase1(TestCase, BaseAPITestCase): # test empty payload self.post(self.login_url, data={}, status_code=400) + def test_login_by_email(self): + # starting test without allauth app + settings.INSTALLED_APPS.remove('allauth') + + payload = { + "email": self.EMAIL.lower(), + "password": self.PASS + } + # there is no users in db so it should throw error (400) + self.post(self.login_url, data=payload, status_code=400) + + self.post(self.password_change_url, status_code=403) + + # create user + user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS) + + # test auth by email + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('key' in self.response.json.keys(), True) + self.token = self.response.json['key'] + + # test auth by email in different case + payload = { + "email": self.EMAIL.upper(), + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=200) + self.assertEqual('key' in self.response.json.keys(), True) + self.token = self.response.json['key'] + + # test inactive user + user.is_active = False + user.save() + self.post(self.login_url, data=payload, status_code=400) + + # test wrong email/password + payload = { + "email": 't' + self.EMAIL, + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=400) + + # test empty payload + self.post(self.login_url, data={}, status_code=400) + def test_password_change(self): login_payload = { "username": self.USERNAME, From 54eb54ad653e9d10cc7ad0d8fa243b0d3ac8cde6 Mon Sep 17 00:00:00 2001 From: mario Date: Wed, 6 Jan 2016 01:18:13 +0100 Subject: [PATCH 2/2] Cleaned up LoginSerializer codebase --- docs/api_endpoints.rst | 1 + rest_auth/serializers.py | 77 ++++++++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index 48e475e..6141653 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -7,6 +7,7 @@ Basic - /rest-auth/login/ (POST) - username (string) + - email (string) - password (string) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index 5bf1ac2..0fd6eab 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -19,50 +19,73 @@ class LoginSerializer(serializers.Serializer): email = serializers.EmailField(required=False, allow_blank=True) password = serializers.CharField(style={'input_type': 'password'}) + def _validate_email(self, email, password): + user = None + + if email and password: + user = authenticate(email=email, password=password) + else: + msg = _('Must include "email" and "password".') + raise exceptions.ValidationError(msg) + + return user + + def _validate_username(self, username, password): + user = None + + if username and password: + user = authenticate(username=username, password=password) + else: + msg = _('Must include "username" and "password".') + raise exceptions.ValidationError(msg) + + return user + + def _validate_username_email(self, username, email, password): + user = None + + if email and password: + user = authenticate(email=email, password=password) + elif username and password: + user = authenticate(username=username, password=password) + else: + msg = _('Must include either "username" or "email" and "password".') + raise exceptions.ValidationError(msg) + + return user + def validate(self, attrs): username = attrs.get('username') email = attrs.get('email') password = attrs.get('password') + user = None + if 'allauth' in settings.INSTALLED_APPS: from allauth.account import app_settings + # Authentication through email if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.EMAIL: - if email and password: - user = authenticate(email=email, password=password) - else: - msg = _('Must include "email" and "password".') - raise exceptions.ValidationError(msg) + user = self._validate_email(email, password) + # Authentication through username - elif app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME: - if username and password: - user = authenticate(username=username, password=password) - else: - msg = _('Must include "username" and "password".') - raise exceptions.ValidationError(msg) + if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME: + user = self._validate_username(username, password) + # Authentication through either username or email else: - if email and password: - user = authenticate(email=email, password=password) - elif username and password: - user = authenticate(username=username, password=password) - else: - msg = _('Must include either "username" or "email" and "password".') - raise exceptions.ValidationError(msg) + user = self._validate_username_email(username, email, password) - elif username or email and password: - # Try get username if we have in request email - if email and not username: + else: + # Authentication without using allauth + if email: try: username = UserModel.objects.get(email__iexact=email).username except UserModel.DoesNotExist: - user = None - if username: - user = authenticate(username=username, password=password) + pass - else: - msg = _('Must include either "username" or "email" and "password".') - raise exceptions.ValidationError(msg) + if username: + user = self._validate_username_email(username, '', password) # Did we get back an active user? if user: