From f9f9d5605f565f47e30b6d62a9146bafa8b1f6bd Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:18:03 +0300 Subject: [PATCH 01/26] Social login also accepts an authentication code instead of an access token. --- docs/api_endpoints.rst | 1 + rest_auth/registration/serializers.py | 34 ++++++++++++++++++++++++--- rest_auth/registration/views.py | 16 ++++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index 05e86919..1b55bb3b 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -73,3 +73,4 @@ Basing on example from installation section :doc:`Installation ` - /rest-auth/facebook/ (POST) - access_token + - code diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 2de467ef..158e6caa 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -9,15 +9,17 @@ class SocialLoginSerializer(serializers.Serializer): access_token = serializers.CharField(required=True) def validate(self, attrs): - access_token = attrs.get('access_token') + view = self.context.get('view') request = self.context.get('request') if not isinstance(request, HttpRequest): request = request._request if not view: - raise serializers.ValidationError('View is not defined, pass it ' + - 'as a context variable') + raise serializers.ValidationError( + 'View is not defined, pass it ' + + 'as a context variable' + ) self.adapter_class = getattr(view, 'adapter_class', None) if not self.adapter_class: @@ -25,6 +27,32 @@ def validate(self, attrs): self.adapter = self.adapter_class() app = self.adapter.get_provider().get_app(request) + + # More info on code vs access_token + # http://stackoverflow.com/questions/8666316/facebook-oauth-2-0-code-and-token + # We have the access_token straight + if('access_token' in attrs): + access_token = attrs.get('access_token') + # We did not get the access_token, but authorization code instead + elif('code' in attrs): + code = attrs.get('code') + + callback_url = self.callback_url + + provider = self.adapter.get_provider() + scope = provider.get_scope(request) + client = self.adapter_class( + request, + app.client_id, + app.secret, + self.adapter.access_token_method, + self.adapter.access_token_url, + callback_url, + scope + ) + token = client.get_access_token(code) + access_token = token['access_token'] + token = self.adapter.parse_token({'access_token': access_token}) token.app = app diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 485881c6..ab9c7058 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -72,11 +72,25 @@ def post(self, request, *args, **kwargs): class SocialLogin(Login): """ class used for social authentications - example usage for facebook + example usage for facebook with access_token + ------------- from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter + + class FacebookLogin(SocialLogin): + adapter_class = FacebookOAuth2Adapter + + ------------- + example usage for facebook with code + + from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter + from allauth.socialaccount.providers.oauth2.client import OAuth2Client + class FacebookLogin(SocialLogin): adapter_class = FacebookOAuth2Adapter + client_class = OAuth2Client + callback_url = 'localhost:8000' + ------------- """ serializer_class = SocialLoginSerializer From 8e9ddd9849bb021221968dae7b499ff4a99c0d85 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:20:01 +0300 Subject: [PATCH 02/26] some pep cleaning --- rest_auth/views.py | 58 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 05217cf0..b11f6a4a 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -9,9 +9,14 @@ from rest_framework.authtoken.models import Token from rest_framework.generics import RetrieveUpdateAPIView -from .app_settings import (TokenSerializer, UserDetailsSerializer, - LoginSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer, - PasswordChangeSerializer) +from .app_settings import ( + TokenSerializer, + UserDetailsSerializer, + LoginSerializer, + PasswordResetSerializer, + PasswordResetConfirmSerializer, + PasswordChangeSerializer, +) class Login(GenericAPIView): @@ -38,12 +43,16 @@ def login(self): login(self.request, self.user) def get_response(self): - return Response(self.response_serializer(self.token).data, - status=status.HTTP_200_OK) + return Response( + self.response_serializer(self.token).data, + status=status.HTTP_200_OK + ) def get_error_response(self): - return Response(self.serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + self.serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) def post(self, request, *args, **kwargs): self.serializer = self.get_serializer(data=self.request.DATA) @@ -71,8 +80,10 @@ def post(self, request): logout(request) - return Response({"success": "Successfully logged out."}, - status=status.HTTP_200_OK) + return Response( + {"success": "Successfully logged out."}, + status=status.HTTP_200_OK + ) class UserDetails(RetrieveUpdateAPIView): @@ -114,14 +125,17 @@ def post(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST) serializer.save() # Return the success message with OK HTTP status - return Response({"success": "Password reset e-mail has been sent."}, - status=status.HTTP_200_OK) + return Response( + {"success": "Password reset e-mail has been sent."}, + status=status.HTTP_200_OK + ) class PasswordResetConfirm(GenericAPIView): """ - Password reset e-mail link is confirmed, therefore this resets the user's password. + Password reset e-mail link is confirmed, + therefore this resets the user's password. Accepts the following POST parameters: new_password1, new_password2 Accepts the following Django URL arguments: token, uid @@ -134,10 +148,14 @@ class PasswordResetConfirm(GenericAPIView): def post(self, request): serializer = self.get_serializer(data=request.DATA) if not serializer.is_valid(): - return Response(serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) serializer.save() - return Response({"success": "Password has been reset with the new password."}) + return Response( + {"success": "Password has been reset with the new password."} + ) class PasswordChange(GenericAPIView): @@ -155,7 +173,11 @@ class PasswordChange(GenericAPIView): def post(self, request): serializer = self.get_serializer(data=request.DATA) if not serializer.is_valid(): - return Response(serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) serializer.save() - return Response({"success": "New password has been saved."}) + return Response( + {"success": "New password has been saved."} + ) From 8c7445904c9b8325f46bb5a9eff9491b2a6731b4 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:21:30 +0300 Subject: [PATCH 03/26] dummy auth provider to ensure that not logged in users can have access --- rest_auth/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rest_auth/views.py b/rest_auth/views.py index b11f6a4a..3b6c7e57 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -8,6 +8,7 @@ from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.authtoken.models import Token from rest_framework.generics import RetrieveUpdateAPIView +from rest_framework.authentication import SessionAuthentication from .app_settings import ( TokenSerializer, @@ -19,6 +20,12 @@ ) +# http://bytefilia.com/titanium-mobile-facebook-application-django-allauth-sign-sign/ +class EverybodyCanAuthentication(SessionAuthentication): + def authenticate(self, request): + return None + + class Login(GenericAPIView): """ @@ -31,6 +38,7 @@ class Login(GenericAPIView): Return the REST Framework Token Object's key. """ permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token response_serializer = TokenSerializer From 482e6becd9e88caa09d0210df6e3c5d741a02927 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:28:22 +0300 Subject: [PATCH 04/26] Bugfix serializer --- rest_auth/registration/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 158e6caa..20617538 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -6,7 +6,8 @@ class SocialLoginSerializer(serializers.Serializer): - access_token = serializers.CharField(required=True) + access_token = serializers.CharField(required=False) + code = serializers.CharField(required=False) def validate(self, attrs): From 664a4a0860f408284999dda28014dde588867fb6 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:34:21 +0300 Subject: [PATCH 05/26] callback url fix --- rest_auth/registration/serializers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 20617538..6d565999 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -36,9 +36,14 @@ def validate(self, attrs): access_token = attrs.get('access_token') # We did not get the access_token, but authorization code instead elif('code' in attrs): - code = attrs.get('code') + self.callback_url = getattr(view, 'callback_url', None) + + if not self.callback_url: + raise serializers.ValidationError( + 'Define callback_url in view' + ) - callback_url = self.callback_url + code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) @@ -48,7 +53,7 @@ def validate(self, attrs): app.secret, self.adapter.access_token_method, self.adapter.access_token_url, - callback_url, + self.callback_url, scope ) token = client.get_access_token(code) From db0b509963937e322604007a025b7bbedc655753 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:39:38 +0300 Subject: [PATCH 06/26] client class --- rest_auth/registration/serializers.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 6d565999..6fe550bb 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -37,17 +37,24 @@ def validate(self, attrs): # We did not get the access_token, but authorization code instead elif('code' in attrs): self.callback_url = getattr(view, 'callback_url', None) + self.client_class = getattr(view, 'client_class', None) if not self.callback_url: raise serializers.ValidationError( 'Define callback_url in view' ) + if not self.client_class: + raise serializers.ValidationError( + 'Define client_class in view' + ) + self.client = self.client_class() + code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) - client = self.adapter_class( + client = self.client( request, app.client_id, app.secret, From 724f17d91ee5a3c0537972c865c4c276cd102b9f Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Mon, 13 Apr 2015 00:49:53 +0300 Subject: [PATCH 07/26] client class fix --- rest_auth/registration/serializers.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 6fe550bb..54e81175 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -48,13 +48,12 @@ def validate(self, attrs): raise serializers.ValidationError( 'Define client_class in view' ) - self.client = self.client_class() code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) - client = self.client( + client = self.client_class( request, app.client_id, app.secret, @@ -70,8 +69,12 @@ def validate(self, attrs): token.app = app try: - login = self.adapter.complete_login(request, app, token, - response=access_token) + login = self.adapter.complete_login( + request, + app, + token, + response=access_token, + ) token.account = login.account login.token = token complete_social_login(request, login) From 901173a46893f34ccfee3d9ad5ee4a9195927a39 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Mon, 13 Apr 2015 19:14:21 +0300 Subject: [PATCH 08/26] config error msg --- rest_auth/registration/serializers.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 54e81175..866f82c9 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -24,7 +24,9 @@ def validate(self, attrs): self.adapter_class = getattr(view, 'adapter_class', None) if not self.adapter_class: - raise serializers.ValidationError('Define adapter_class in view') + raise serializers.ValidationError( + 'Define adapter_class in view' + ) self.adapter = self.adapter_class() app = self.adapter.get_provider().get_app(request) @@ -39,6 +41,15 @@ def validate(self, attrs): self.callback_url = getattr(view, 'callback_url', None) self.client_class = getattr(view, 'client_class', None) + if not self.callback_url: + raise serializers.ValidationError( + 'Define callback_url in view' + ) + if not self.client_class: + raise serializers.ValidationError( + 'Define client_class in view' + ) + if not self.callback_url: raise serializers.ValidationError( 'Define callback_url in view' From 64504395203dfddfe9c1392c674e13ce95a9d418 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 12:00:58 +0300 Subject: [PATCH 09/26] user added to response on login --- rest_auth/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 3b6c7e57..94f46098 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -41,7 +41,8 @@ class Login(GenericAPIView): authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token - response_serializer = TokenSerializer + token_serializer = TokenSerializer + user_serializer = UserDetailsSerializer def login(self): self.user = self.serializer.validated_data['user'] @@ -51,8 +52,11 @@ def login(self): login(self.request, self.user) def get_response(self): + response = self.token_serializer(self.token).data + user = self.user_serializer(instance=self.user).data + response['user'] = user return Response( - self.response_serializer(self.token).data, + response, status=status.HTTP_200_OK ) From 71a10712085782bed83ae688a61515d1984f9ddb Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 12:12:28 +0300 Subject: [PATCH 10/26] register update --- rest_auth/registration/views.py | 35 ++++++++++++++++++++++++++++----- rest_auth/views.py | 6 ++++-- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index ab9c7058..2642e8f7 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -2,21 +2,42 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import AllowAny +from rest_framework.authtoken.models import Token from rest_framework import status from allauth.account.views import SignupView, ConfirmEmailView from allauth.account.utils import complete_signup from allauth.account import app_settings -from rest_auth.app_settings import UserDetailsSerializer +from rest_auth.app_settings import ( + UserDetailsSerializer, + TokenSerializer, +) from rest_auth.registration.serializers import SocialLoginSerializer -from rest_auth.views import Login +from rest_auth.views import ( + Login, + EverybodyCanAuthentication, +) class Register(APIView, SignupView): + """ + Accepts the credentials and creates a new user + if user does not exist already + Return the REST Token and the user object + if the credentials are valid and authenticated. + Calls allauth complete_signup method + + Accept the following POST parameters: username, password + Return the REST Framework Token Object's key + and user object. + """ permission_classes = (AllowAny,) - user_serializer_class = UserDetailsSerializer + authentication_classes = (EverybodyCanAuthentication,) + token_model = Token + token_serializer = TokenSerializer + user_serializer = UserDetailsSerializer allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): @@ -27,6 +48,8 @@ def put(self, *args, **kwargs): def form_valid(self, form): self.user = form.save(self.request) + self.token, created = self.token_model.objects.get_or_create( + user=self.user) if isinstance(self.request, HttpRequest): request = self.request else: @@ -47,8 +70,10 @@ def post(self, request, *args, **kwargs): return self.get_response_with_errors() def get_response(self): - serializer = self.user_serializer_class(instance=self.user) - return Response(serializer.data, status=status.HTTP_201_CREATED) + response = self.token_serializer(self.token).data + user = self.user_serializer(instance=self.user).data + response['user'] = user + return Response(response, status=status.HTTP_201_CREATED) def get_response_with_errors(self): return Response(self.form.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/rest_auth/views.py b/rest_auth/views.py index 94f46098..33d93b15 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -27,16 +27,18 @@ def authenticate(self, request): class Login(GenericAPIView): - """ Check the credentials and return the REST Token + and the user object if the credentials are valid and authenticated. Calls Django Auth login method to register User ID in Django session framework Accept the following POST parameters: username, password - Return the REST Framework Token Object's key. + Return the REST Framework Token Object's key + and user object. """ + permission_classes = (AllowAny,) authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer From 38607cdc113cffd30c5e8b0cfd3d823e8457f620 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 13:10:53 +0300 Subject: [PATCH 11/26] now I get why response_serializer is used... --- rest_auth/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 33d93b15..b0ed2130 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -43,7 +43,7 @@ class Login(GenericAPIView): authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token - token_serializer = TokenSerializer + response_serializer = TokenSerializer user_serializer = UserDetailsSerializer def login(self): @@ -54,7 +54,7 @@ def login(self): login(self.request, self.user) def get_response(self): - response = self.token_serializer(self.token).data + response = self.response_serializer(self.token).data user = self.user_serializer(instance=self.user).data response['user'] = user return Response( From cd20ad484659ab06b26494ea0f6ab765432fd377 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Wed, 15 Apr 2015 17:25:32 +0300 Subject: [PATCH 12/26] login through email possible, checking allauth settings --- rest_auth/registration/views.py | 4 +- rest_auth/serializers.py | 85 +++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 2642e8f7..3dada33a 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -37,7 +37,7 @@ class Register(APIView, SignupView): authentication_classes = (EverybodyCanAuthentication,) token_model = Token token_serializer = TokenSerializer - user_serializer = UserDetailsSerializer + user_serializer_class = UserDetailsSerializer allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): @@ -71,7 +71,7 @@ def post(self, request, *args, **kwargs): def get_response(self): response = self.token_serializer(self.token).data - user = self.user_serializer(instance=self.user).data + user = self.user_serializer_class(instance=self.user).data response['user'] = user return Response(response, status=status.HTTP_201_CREATED) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index e0ab9090..d3955f89 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -1,5 +1,7 @@ from django.contrib.auth import get_user_model +from django.contrib.auth import authenticate from django.conf import settings +from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm try: from django.utils.http import urlsafe_base64_decode as uid_decoder @@ -8,16 +10,76 @@ from django.utils.http import base36_to_int as uid_decoder from django.contrib.auth.tokens import default_token_generator -from rest_framework import serializers +from rest_framework import ( + exceptions, + serializers, +) from rest_framework.authtoken.models import Token -from rest_framework.authtoken.serializers import AuthTokenSerializer +# from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework.exceptions import ValidationError -class LoginSerializer(AuthTokenSerializer): +class LoginSerializer(serializers.Serializer): + username = serializers.CharField(required=False) + email = serializers.EmailField(required=False) + password = serializers.CharField(style={'input_type': 'password'}) def validate(self, attrs): - attrs = super(LoginSerializer, self).validate(attrs) + username = attrs.get('username') + email = attrs.get('email') + password = attrs.get('password') + + 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) + # 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) + # 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) + + if user: + if not user.is_active: + msg = _('User account is disabled.') + raise exceptions.ValidationError(msg) + else: + msg = _('Unable to log in with provided credentials.') + raise exceptions.ValidationError(msg) + + elif username and password: + user = authenticate(username=username, password=password) + + if user: + if not user.is_active: + msg = _('User account is disabled.') + raise exceptions.ValidationError(msg) + else: + msg = _('Unable to log in with provided credentials.') + raise exceptions.ValidationError(msg) + else: + msg = _('Must include "username" and "password".') + raise exceptions.ValidationError(msg) + + attrs['user'] = user + if 'rest_auth.registration' in settings.INSTALLED_APPS: from allauth.account import app_settings if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY: @@ -25,9 +87,24 @@ def validate(self, attrs): email_address = user.emailaddress_set.get(email=user.email) if not email_address.verified: raise serializers.ValidationError('E-mail is not verified.') + return attrs +# class LoginSerializer(AuthTokenSerializer): + +# def validate(self, attrs): +# attrs = super(LoginSerializer, self).validate(attrs) +# if 'rest_auth.registration' in settings.INSTALLED_APPS: +# from allauth.account import app_settings +# if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY: +# user = attrs['user'] +# email_address = user.emailaddress_set.get(email=user.email) +# if not email_address.verified: +# raise serializers.ValidationError('E-mail is not verified.') +# return attrs + + class TokenSerializer(serializers.ModelSerializer): """ Serializer for Token model. From bb5ac3e7eab54afd97b2454b9903ffc0d2ce553f Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:18:03 +0300 Subject: [PATCH 13/26] Social login also accepts an authentication code instead of an access token. --- docs/api_endpoints.rst | 1 + rest_auth/registration/serializers.py | 34 ++++++++++++++++++++++++--- rest_auth/registration/views.py | 16 ++++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/docs/api_endpoints.rst b/docs/api_endpoints.rst index 05e86919..1b55bb3b 100644 --- a/docs/api_endpoints.rst +++ b/docs/api_endpoints.rst @@ -73,3 +73,4 @@ Basing on example from installation section :doc:`Installation ` - /rest-auth/facebook/ (POST) - access_token + - code diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 2de467ef..158e6caa 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -9,15 +9,17 @@ class SocialLoginSerializer(serializers.Serializer): access_token = serializers.CharField(required=True) def validate(self, attrs): - access_token = attrs.get('access_token') + view = self.context.get('view') request = self.context.get('request') if not isinstance(request, HttpRequest): request = request._request if not view: - raise serializers.ValidationError('View is not defined, pass it ' + - 'as a context variable') + raise serializers.ValidationError( + 'View is not defined, pass it ' + + 'as a context variable' + ) self.adapter_class = getattr(view, 'adapter_class', None) if not self.adapter_class: @@ -25,6 +27,32 @@ def validate(self, attrs): self.adapter = self.adapter_class() app = self.adapter.get_provider().get_app(request) + + # More info on code vs access_token + # http://stackoverflow.com/questions/8666316/facebook-oauth-2-0-code-and-token + # We have the access_token straight + if('access_token' in attrs): + access_token = attrs.get('access_token') + # We did not get the access_token, but authorization code instead + elif('code' in attrs): + code = attrs.get('code') + + callback_url = self.callback_url + + provider = self.adapter.get_provider() + scope = provider.get_scope(request) + client = self.adapter_class( + request, + app.client_id, + app.secret, + self.adapter.access_token_method, + self.adapter.access_token_url, + callback_url, + scope + ) + token = client.get_access_token(code) + access_token = token['access_token'] + token = self.adapter.parse_token({'access_token': access_token}) token.app = app diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 485881c6..ab9c7058 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -72,11 +72,25 @@ def post(self, request, *args, **kwargs): class SocialLogin(Login): """ class used for social authentications - example usage for facebook + example usage for facebook with access_token + ------------- from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter + + class FacebookLogin(SocialLogin): + adapter_class = FacebookOAuth2Adapter + + ------------- + example usage for facebook with code + + from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter + from allauth.socialaccount.providers.oauth2.client import OAuth2Client + class FacebookLogin(SocialLogin): adapter_class = FacebookOAuth2Adapter + client_class = OAuth2Client + callback_url = 'localhost:8000' + ------------- """ serializer_class = SocialLoginSerializer From c7ef9eb775c95d4d9d98e3547edc053a7766bc79 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:20:01 +0300 Subject: [PATCH 14/26] some pep cleaning --- rest_auth/views.py | 58 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 05217cf0..b11f6a4a 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -9,9 +9,14 @@ from rest_framework.authtoken.models import Token from rest_framework.generics import RetrieveUpdateAPIView -from .app_settings import (TokenSerializer, UserDetailsSerializer, - LoginSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer, - PasswordChangeSerializer) +from .app_settings import ( + TokenSerializer, + UserDetailsSerializer, + LoginSerializer, + PasswordResetSerializer, + PasswordResetConfirmSerializer, + PasswordChangeSerializer, +) class Login(GenericAPIView): @@ -38,12 +43,16 @@ def login(self): login(self.request, self.user) def get_response(self): - return Response(self.response_serializer(self.token).data, - status=status.HTTP_200_OK) + return Response( + self.response_serializer(self.token).data, + status=status.HTTP_200_OK + ) def get_error_response(self): - return Response(self.serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + self.serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) def post(self, request, *args, **kwargs): self.serializer = self.get_serializer(data=self.request.DATA) @@ -71,8 +80,10 @@ def post(self, request): logout(request) - return Response({"success": "Successfully logged out."}, - status=status.HTTP_200_OK) + return Response( + {"success": "Successfully logged out."}, + status=status.HTTP_200_OK + ) class UserDetails(RetrieveUpdateAPIView): @@ -114,14 +125,17 @@ def post(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST) serializer.save() # Return the success message with OK HTTP status - return Response({"success": "Password reset e-mail has been sent."}, - status=status.HTTP_200_OK) + return Response( + {"success": "Password reset e-mail has been sent."}, + status=status.HTTP_200_OK + ) class PasswordResetConfirm(GenericAPIView): """ - Password reset e-mail link is confirmed, therefore this resets the user's password. + Password reset e-mail link is confirmed, + therefore this resets the user's password. Accepts the following POST parameters: new_password1, new_password2 Accepts the following Django URL arguments: token, uid @@ -134,10 +148,14 @@ class PasswordResetConfirm(GenericAPIView): def post(self, request): serializer = self.get_serializer(data=request.DATA) if not serializer.is_valid(): - return Response(serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) serializer.save() - return Response({"success": "Password has been reset with the new password."}) + return Response( + {"success": "Password has been reset with the new password."} + ) class PasswordChange(GenericAPIView): @@ -155,7 +173,11 @@ class PasswordChange(GenericAPIView): def post(self, request): serializer = self.get_serializer(data=request.DATA) if not serializer.is_valid(): - return Response(serializer.errors, - status=status.HTTP_400_BAD_REQUEST) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST + ) serializer.save() - return Response({"success": "New password has been saved."}) + return Response( + {"success": "New password has been saved."} + ) From 84ac7e90da553730349150627a002cc41e5c7b1e Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:21:30 +0300 Subject: [PATCH 15/26] dummy auth provider to ensure that not logged in users can have access --- rest_auth/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rest_auth/views.py b/rest_auth/views.py index b11f6a4a..3b6c7e57 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -8,6 +8,7 @@ from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.authtoken.models import Token from rest_framework.generics import RetrieveUpdateAPIView +from rest_framework.authentication import SessionAuthentication from .app_settings import ( TokenSerializer, @@ -19,6 +20,12 @@ ) +# http://bytefilia.com/titanium-mobile-facebook-application-django-allauth-sign-sign/ +class EverybodyCanAuthentication(SessionAuthentication): + def authenticate(self, request): + return None + + class Login(GenericAPIView): """ @@ -31,6 +38,7 @@ class Login(GenericAPIView): Return the REST Framework Token Object's key. """ permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token response_serializer = TokenSerializer From b65ce1770a06d9ab358fe188b85b8804650534ef Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:28:22 +0300 Subject: [PATCH 16/26] Bugfix serializer --- rest_auth/registration/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 158e6caa..20617538 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -6,7 +6,8 @@ class SocialLoginSerializer(serializers.Serializer): - access_token = serializers.CharField(required=True) + access_token = serializers.CharField(required=False) + code = serializers.CharField(required=False) def validate(self, attrs): From 55cc830fdb12bbaa82d400f9a40e90bd09bfc901 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:34:21 +0300 Subject: [PATCH 17/26] callback url fix --- rest_auth/registration/serializers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 20617538..6d565999 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -36,9 +36,14 @@ def validate(self, attrs): access_token = attrs.get('access_token') # We did not get the access_token, but authorization code instead elif('code' in attrs): - code = attrs.get('code') + self.callback_url = getattr(view, 'callback_url', None) + + if not self.callback_url: + raise serializers.ValidationError( + 'Define callback_url in view' + ) - callback_url = self.callback_url + code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) @@ -48,7 +53,7 @@ def validate(self, attrs): app.secret, self.adapter.access_token_method, self.adapter.access_token_url, - callback_url, + self.callback_url, scope ) token = client.get_access_token(code) From 68c0a7f87cd3119228a7cb90ba3ce28828e6b4e7 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Sun, 12 Apr 2015 20:39:38 +0300 Subject: [PATCH 18/26] client class --- rest_auth/registration/serializers.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 6d565999..6fe550bb 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -37,17 +37,24 @@ def validate(self, attrs): # We did not get the access_token, but authorization code instead elif('code' in attrs): self.callback_url = getattr(view, 'callback_url', None) + self.client_class = getattr(view, 'client_class', None) if not self.callback_url: raise serializers.ValidationError( 'Define callback_url in view' ) + if not self.client_class: + raise serializers.ValidationError( + 'Define client_class in view' + ) + self.client = self.client_class() + code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) - client = self.adapter_class( + client = self.client( request, app.client_id, app.secret, From dcd88a3f873b6f8f8f90ed612c0af1eb6d659c60 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Mon, 13 Apr 2015 00:49:53 +0300 Subject: [PATCH 19/26] client class fix --- rest_auth/registration/serializers.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 6fe550bb..54e81175 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -48,13 +48,12 @@ def validate(self, attrs): raise serializers.ValidationError( 'Define client_class in view' ) - self.client = self.client_class() code = attrs.get('code') provider = self.adapter.get_provider() scope = provider.get_scope(request) - client = self.client( + client = self.client_class( request, app.client_id, app.secret, @@ -70,8 +69,12 @@ def validate(self, attrs): token.app = app try: - login = self.adapter.complete_login(request, app, token, - response=access_token) + login = self.adapter.complete_login( + request, + app, + token, + response=access_token, + ) token.account = login.account login.token = token complete_social_login(request, login) From eb616d107a643463a94f19c72347ba03daca082f Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Mon, 13 Apr 2015 19:14:21 +0300 Subject: [PATCH 20/26] config error msg --- rest_auth/registration/serializers.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rest_auth/registration/serializers.py b/rest_auth/registration/serializers.py index 54e81175..866f82c9 100644 --- a/rest_auth/registration/serializers.py +++ b/rest_auth/registration/serializers.py @@ -24,7 +24,9 @@ def validate(self, attrs): self.adapter_class = getattr(view, 'adapter_class', None) if not self.adapter_class: - raise serializers.ValidationError('Define adapter_class in view') + raise serializers.ValidationError( + 'Define adapter_class in view' + ) self.adapter = self.adapter_class() app = self.adapter.get_provider().get_app(request) @@ -39,6 +41,15 @@ def validate(self, attrs): self.callback_url = getattr(view, 'callback_url', None) self.client_class = getattr(view, 'client_class', None) + if not self.callback_url: + raise serializers.ValidationError( + 'Define callback_url in view' + ) + if not self.client_class: + raise serializers.ValidationError( + 'Define client_class in view' + ) + if not self.callback_url: raise serializers.ValidationError( 'Define callback_url in view' From 75f67aad0572b8abb7a80d552166940329a4c2c2 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 12:00:58 +0300 Subject: [PATCH 21/26] user added to response on login --- rest_auth/views.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 3b6c7e57..94f46098 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -41,7 +41,8 @@ class Login(GenericAPIView): authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token - response_serializer = TokenSerializer + token_serializer = TokenSerializer + user_serializer = UserDetailsSerializer def login(self): self.user = self.serializer.validated_data['user'] @@ -51,8 +52,11 @@ def login(self): login(self.request, self.user) def get_response(self): + response = self.token_serializer(self.token).data + user = self.user_serializer(instance=self.user).data + response['user'] = user return Response( - self.response_serializer(self.token).data, + response, status=status.HTTP_200_OK ) From 2fff7a6254f370fcdc7bfdcd3ee538a8ac790237 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 12:12:28 +0300 Subject: [PATCH 22/26] register update --- rest_auth/registration/views.py | 35 ++++++++++++++++++++++++++++----- rest_auth/views.py | 6 ++++-- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index ab9c7058..2642e8f7 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -2,21 +2,42 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import AllowAny +from rest_framework.authtoken.models import Token from rest_framework import status from allauth.account.views import SignupView, ConfirmEmailView from allauth.account.utils import complete_signup from allauth.account import app_settings -from rest_auth.app_settings import UserDetailsSerializer +from rest_auth.app_settings import ( + UserDetailsSerializer, + TokenSerializer, +) from rest_auth.registration.serializers import SocialLoginSerializer -from rest_auth.views import Login +from rest_auth.views import ( + Login, + EverybodyCanAuthentication, +) class Register(APIView, SignupView): + """ + Accepts the credentials and creates a new user + if user does not exist already + Return the REST Token and the user object + if the credentials are valid and authenticated. + Calls allauth complete_signup method + + Accept the following POST parameters: username, password + Return the REST Framework Token Object's key + and user object. + """ permission_classes = (AllowAny,) - user_serializer_class = UserDetailsSerializer + authentication_classes = (EverybodyCanAuthentication,) + token_model = Token + token_serializer = TokenSerializer + user_serializer = UserDetailsSerializer allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): @@ -27,6 +48,8 @@ def put(self, *args, **kwargs): def form_valid(self, form): self.user = form.save(self.request) + self.token, created = self.token_model.objects.get_or_create( + user=self.user) if isinstance(self.request, HttpRequest): request = self.request else: @@ -47,8 +70,10 @@ def post(self, request, *args, **kwargs): return self.get_response_with_errors() def get_response(self): - serializer = self.user_serializer_class(instance=self.user) - return Response(serializer.data, status=status.HTTP_201_CREATED) + response = self.token_serializer(self.token).data + user = self.user_serializer(instance=self.user).data + response['user'] = user + return Response(response, status=status.HTTP_201_CREATED) def get_response_with_errors(self): return Response(self.form.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/rest_auth/views.py b/rest_auth/views.py index 94f46098..33d93b15 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -27,16 +27,18 @@ def authenticate(self, request): class Login(GenericAPIView): - """ Check the credentials and return the REST Token + and the user object if the credentials are valid and authenticated. Calls Django Auth login method to register User ID in Django session framework Accept the following POST parameters: username, password - Return the REST Framework Token Object's key. + Return the REST Framework Token Object's key + and user object. """ + permission_classes = (AllowAny,) authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer From 4b188023ff277640afd6ef8869d926eeb3827e03 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Tue, 14 Apr 2015 13:10:53 +0300 Subject: [PATCH 23/26] now I get why response_serializer is used... --- rest_auth/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_auth/views.py b/rest_auth/views.py index 33d93b15..b0ed2130 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -43,7 +43,7 @@ class Login(GenericAPIView): authentication_classes = (EverybodyCanAuthentication,) serializer_class = LoginSerializer token_model = Token - token_serializer = TokenSerializer + response_serializer = TokenSerializer user_serializer = UserDetailsSerializer def login(self): @@ -54,7 +54,7 @@ def login(self): login(self.request, self.user) def get_response(self): - response = self.token_serializer(self.token).data + response = self.response_serializer(self.token).data user = self.user_serializer(instance=self.user).data response['user'] = user return Response( From a18c45045ed98b79276c03c7ecb3809d10e08057 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Wed, 15 Apr 2015 17:25:32 +0300 Subject: [PATCH 24/26] login through email possible, checking allauth settings --- rest_auth/registration/views.py | 4 +- rest_auth/serializers.py | 85 +++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 2642e8f7..3dada33a 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -37,7 +37,7 @@ class Register(APIView, SignupView): authentication_classes = (EverybodyCanAuthentication,) token_model = Token token_serializer = TokenSerializer - user_serializer = UserDetailsSerializer + user_serializer_class = UserDetailsSerializer allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): @@ -71,7 +71,7 @@ def post(self, request, *args, **kwargs): def get_response(self): response = self.token_serializer(self.token).data - user = self.user_serializer(instance=self.user).data + user = self.user_serializer_class(instance=self.user).data response['user'] = user return Response(response, status=status.HTTP_201_CREATED) diff --git a/rest_auth/serializers.py b/rest_auth/serializers.py index db1e4cb7..917a3fb5 100644 --- a/rest_auth/serializers.py +++ b/rest_auth/serializers.py @@ -1,5 +1,7 @@ from django.contrib.auth import get_user_model +from django.contrib.auth import authenticate from django.conf import settings +from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm try: from django.utils.http import urlsafe_base64_decode as uid_decoder @@ -8,16 +10,76 @@ from django.utils.http import base36_to_int as uid_decoder from django.contrib.auth.tokens import default_token_generator -from rest_framework import serializers +from rest_framework import ( + exceptions, + serializers, +) from rest_framework.authtoken.models import Token -from rest_framework.authtoken.serializers import AuthTokenSerializer +# from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework.exceptions import ValidationError -class LoginSerializer(AuthTokenSerializer): +class LoginSerializer(serializers.Serializer): + username = serializers.CharField(required=False) + email = serializers.EmailField(required=False) + password = serializers.CharField(style={'input_type': 'password'}) def validate(self, attrs): - attrs = super(LoginSerializer, self).validate(attrs) + username = attrs.get('username') + email = attrs.get('email') + password = attrs.get('password') + + 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) + # 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) + # 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) + + if user: + if not user.is_active: + msg = _('User account is disabled.') + raise exceptions.ValidationError(msg) + else: + msg = _('Unable to log in with provided credentials.') + raise exceptions.ValidationError(msg) + + elif username and password: + user = authenticate(username=username, password=password) + + if user: + if not user.is_active: + msg = _('User account is disabled.') + raise exceptions.ValidationError(msg) + else: + msg = _('Unable to log in with provided credentials.') + raise exceptions.ValidationError(msg) + else: + msg = _('Must include "username" and "password".') + raise exceptions.ValidationError(msg) + + attrs['user'] = user + if 'rest_auth.registration' in settings.INSTALLED_APPS: from allauth.account import app_settings if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY: @@ -25,9 +87,24 @@ def validate(self, attrs): email_address = user.emailaddress_set.get(email=user.email) if not email_address.verified: raise serializers.ValidationError('E-mail is not verified.') + return attrs +# class LoginSerializer(AuthTokenSerializer): + +# def validate(self, attrs): +# attrs = super(LoginSerializer, self).validate(attrs) +# if 'rest_auth.registration' in settings.INSTALLED_APPS: +# from allauth.account import app_settings +# if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY: +# user = attrs['user'] +# email_address = user.emailaddress_set.get(email=user.email) +# if not email_address.verified: +# raise serializers.ValidationError('E-mail is not verified.') +# return attrs + + class TokenSerializer(serializers.ModelSerializer): """ Serializer for Token model. From ec25bbff0e963f1d6dfcfd38bdf64323e33f723c Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Mon, 27 Apr 2015 19:42:00 +0300 Subject: [PATCH 25/26] everybody can auth --- rest_auth/registration/views.py | 1 + rest_auth/views.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index 3dada33a..cfb6f2cb 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -82,6 +82,7 @@ def get_response_with_errors(self): class VerifyEmail(APIView, ConfirmEmailView): permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): diff --git a/rest_auth/views.py b/rest_auth/views.py index b0ed2130..4d97e904 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -85,6 +85,7 @@ class Logout(APIView): Accepts/Returns nothing. """ permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) def post(self, request): try: @@ -113,6 +114,7 @@ class UserDetails(RetrieveUpdateAPIView): """ serializer_class = UserDetailsSerializer permission_classes = (IsAuthenticated,) + authentication_classes = (EverybodyCanAuthentication,) def get_object(self): return self.request.user @@ -129,6 +131,7 @@ class PasswordReset(GenericAPIView): serializer_class = PasswordResetSerializer permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) def post(self, request, *args, **kwargs): # Create a serializer with request.DATA @@ -158,6 +161,7 @@ class PasswordResetConfirm(GenericAPIView): serializer_class = PasswordResetConfirmSerializer permission_classes = (AllowAny,) + authentication_classes = (EverybodyCanAuthentication,) def post(self, request): serializer = self.get_serializer(data=request.DATA) @@ -183,6 +187,7 @@ class PasswordChange(GenericAPIView): serializer_class = PasswordChangeSerializer permission_classes = (IsAuthenticated,) + authentication_classes = (EverybodyCanAuthentication,) def post(self, request): serializer = self.get_serializer(data=request.DATA) From 1371eb932e415f6326fd0eb3a4b6f4c15e690c98 Mon Sep 17 00:00:00 2001 From: Philippe Luickx Date: Thu, 30 Apr 2015 13:25:29 +0300 Subject: [PATCH 26/26] cleanup --- rest_auth/registration/views.py | 1 - rest_auth/views.py | 5 ----- 2 files changed, 6 deletions(-) diff --git a/rest_auth/registration/views.py b/rest_auth/registration/views.py index cfb6f2cb..3dada33a 100644 --- a/rest_auth/registration/views.py +++ b/rest_auth/registration/views.py @@ -82,7 +82,6 @@ def get_response_with_errors(self): class VerifyEmail(APIView, ConfirmEmailView): permission_classes = (AllowAny,) - authentication_classes = (EverybodyCanAuthentication,) allowed_methods = ('POST', 'OPTIONS', 'HEAD') def get(self, *args, **kwargs): diff --git a/rest_auth/views.py b/rest_auth/views.py index 437a6965..31cccd4f 100644 --- a/rest_auth/views.py +++ b/rest_auth/views.py @@ -86,7 +86,6 @@ class Logout(APIView): Accepts/Returns nothing. """ permission_classes = (AllowAny,) - authentication_classes = (EverybodyCanAuthentication,) def post(self, request): try: @@ -115,7 +114,6 @@ class UserDetails(RetrieveUpdateAPIView): """ serializer_class = UserDetailsSerializer permission_classes = (IsAuthenticated,) - authentication_classes = (EverybodyCanAuthentication,) def get_object(self): return self.request.user @@ -132,7 +130,6 @@ class PasswordReset(GenericAPIView): serializer_class = PasswordResetSerializer permission_classes = (AllowAny,) - authentication_classes = (EverybodyCanAuthentication,) def post(self, request, *args, **kwargs): # Create a serializer with request.DATA @@ -162,7 +159,6 @@ class PasswordResetConfirm(GenericAPIView): serializer_class = PasswordResetConfirmSerializer permission_classes = (AllowAny,) - authentication_classes = (EverybodyCanAuthentication,) def post(self, request): serializer = self.get_serializer(data=request.DATA) @@ -188,7 +184,6 @@ class PasswordChange(GenericAPIView): serializer_class = PasswordChangeSerializer permission_classes = (IsAuthenticated,) - authentication_classes = (EverybodyCanAuthentication,) def post(self, request): serializer = self.get_serializer(data=request.DATA)