2015-08-07 13:43:21 +03:00
|
|
|
from django.contrib.auth import get_user_model, authenticate
|
2014-04-30 23:52:05 +04:00
|
|
|
from django.conf import settings
|
2014-10-07 17:08:08 +04:00
|
|
|
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
|
|
|
from django.contrib.auth.tokens import default_token_generator
|
2015-11-19 11:38:57 +03:00
|
|
|
from django.utils.http import urlsafe_base64_decode as uid_decoder
|
2015-08-07 13:43:21 +03:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2015-11-19 11:38:57 +03:00
|
|
|
from django.utils.encoding import force_text
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2016-01-01 00:10:52 +03:00
|
|
|
from .models import TokenModel
|
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
from rest_framework import serializers, exceptions
|
2015-01-27 18:52:54 +03:00
|
|
|
from rest_framework.exceptions import ValidationError
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2015-11-19 11:38:57 +03:00
|
|
|
# Get the UserModel
|
|
|
|
UserModel = get_user_model()
|
|
|
|
|
2014-07-08 13:36:59 +04:00
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
class LoginSerializer(serializers.Serializer):
|
2015-08-17 13:35:20 +03:00
|
|
|
username = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
email = serializers.EmailField(required=False, allow_blank=True)
|
2015-08-07 13:43:21 +03:00
|
|
|
password = serializers.CharField(style={'input_type': 'password'})
|
2014-10-01 17:31:10 +04:00
|
|
|
|
2016-01-06 03:18:13 +03:00
|
|
|
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
|
|
|
|
|
2014-10-01 17:31:10 +04:00
|
|
|
def validate(self, attrs):
|
2015-08-07 13:43:21 +03:00
|
|
|
username = attrs.get('username')
|
|
|
|
email = attrs.get('email')
|
|
|
|
password = attrs.get('password')
|
|
|
|
|
2016-01-06 03:18:13 +03:00
|
|
|
user = None
|
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
if 'allauth' in settings.INSTALLED_APPS:
|
|
|
|
from allauth.account import app_settings
|
2016-01-06 03:18:13 +03:00
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
# Authentication through email
|
|
|
|
if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.EMAIL:
|
2016-01-06 03:18:13 +03:00
|
|
|
user = self._validate_email(email, password)
|
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
# Authentication through username
|
2016-01-06 03:18:13 +03:00
|
|
|
if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME:
|
|
|
|
user = self._validate_username(username, password)
|
|
|
|
|
2015-08-07 13:43:21 +03:00
|
|
|
# Authentication through either username or email
|
|
|
|
else:
|
2016-01-06 03:18:13 +03:00
|
|
|
user = self._validate_username_email(username, email, password)
|
2015-08-07 13:43:21 +03:00
|
|
|
|
|
|
|
else:
|
2016-01-06 03:18:13 +03:00
|
|
|
# Authentication without using allauth
|
|
|
|
if email:
|
2015-12-13 23:43:33 +03:00
|
|
|
try:
|
2016-02-17 08:35:47 +03:00
|
|
|
username = UserModel.objects.get(email__iexact=email).get_username()
|
2015-12-13 23:43:33 +03:00
|
|
|
except UserModel.DoesNotExist:
|
2016-01-06 03:18:13 +03:00
|
|
|
pass
|
2015-08-07 13:43:21 +03:00
|
|
|
|
2016-01-06 03:18:13 +03:00
|
|
|
if username:
|
|
|
|
user = self._validate_username_email(username, '', password)
|
2015-08-07 13:43:21 +03:00
|
|
|
|
|
|
|
# Did we get back an active user?
|
|
|
|
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)
|
|
|
|
|
|
|
|
# If required, is the email verified?
|
2014-10-01 17:31:10 +04:00
|
|
|
if 'rest_auth.registration' in settings.INSTALLED_APPS:
|
|
|
|
from allauth.account import app_settings
|
|
|
|
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
|
|
|
|
email_address = user.emailaddress_set.get(email=user.email)
|
|
|
|
if not email_address.verified:
|
2016-02-02 17:29:16 +03:00
|
|
|
raise serializers.ValidationError(_('E-mail is not verified.'))
|
2015-08-07 13:43:21 +03:00
|
|
|
|
|
|
|
attrs['user'] = user
|
2014-10-01 17:31:10 +04:00
|
|
|
return attrs
|
2014-04-30 23:52:05 +04:00
|
|
|
|
|
|
|
|
|
|
|
class TokenSerializer(serializers.ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for Token model.
|
|
|
|
"""
|
|
|
|
|
|
|
|
class Meta:
|
2016-01-01 00:10:52 +03:00
|
|
|
model = TokenModel
|
2014-04-30 23:52:05 +04:00
|
|
|
fields = ('key',)
|
|
|
|
|
2016-03-01 14:51:01 +03:00
|
|
|
|
2014-04-30 23:52:05 +04:00
|
|
|
class UserDetailsSerializer(serializers.ModelSerializer):
|
2014-05-01 00:55:04 +04:00
|
|
|
|
2014-04-30 23:52:05 +04:00
|
|
|
"""
|
|
|
|
User model w/o password
|
|
|
|
"""
|
|
|
|
class Meta:
|
2015-11-24 00:17:32 +03:00
|
|
|
model = UserModel
|
2016-10-17 20:27:03 +03:00
|
|
|
fields = ('pk', 'username', 'email', 'first_name', 'last_name')
|
2015-02-25 18:06:46 +03:00
|
|
|
read_only_fields = ('email', )
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2016-03-01 14:51:01 +03:00
|
|
|
|
2016-01-04 20:45:33 +03:00
|
|
|
class JWTSerializer(serializers.Serializer):
|
|
|
|
"""
|
|
|
|
Serializer for JWT authentication.
|
|
|
|
"""
|
|
|
|
token = serializers.CharField()
|
|
|
|
user = UserDetailsSerializer()
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2016-03-01 14:51:01 +03:00
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
class PasswordResetSerializer(serializers.Serializer):
|
2014-05-01 00:55:04 +04:00
|
|
|
|
2014-04-30 23:52:05 +04:00
|
|
|
"""
|
2014-10-07 17:08:08 +04:00
|
|
|
Serializer for requesting a password reset e-mail.
|
2014-04-30 23:52:05 +04:00
|
|
|
"""
|
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
email = serializers.EmailField()
|
|
|
|
|
|
|
|
password_reset_form_class = PasswordResetForm
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2016-01-15 01:42:02 +03:00
|
|
|
def get_email_options(self):
|
|
|
|
""" Override this method to change default e-mail options
|
|
|
|
"""
|
|
|
|
return {}
|
|
|
|
|
2015-01-09 14:05:14 +03:00
|
|
|
def validate_email(self, value):
|
2014-10-07 17:08:08 +04:00
|
|
|
# Create PasswordResetForm with the serializer
|
2015-01-09 14:05:14 +03:00
|
|
|
self.reset_form = self.password_reset_form_class(data=self.initial_data)
|
2014-10-07 17:08:08 +04:00
|
|
|
if not self.reset_form.is_valid():
|
2016-02-10 19:45:32 +03:00
|
|
|
raise serializers.ValidationError(self.reset_form.errors)
|
2015-11-24 00:17:32 +03:00
|
|
|
|
2015-01-09 14:05:14 +03:00
|
|
|
return value
|
2014-05-05 23:01:23 +04:00
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
def save(self):
|
|
|
|
request = self.context.get('request')
|
|
|
|
# Set some values to trigger the send_email method.
|
|
|
|
opts = {
|
|
|
|
'use_https': request.is_secure(),
|
|
|
|
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
|
|
|
|
'request': request,
|
|
|
|
}
|
2016-01-15 01:42:02 +03:00
|
|
|
|
|
|
|
opts.update(self.get_email_options())
|
2014-10-07 17:08:08 +04:00
|
|
|
self.reset_form.save(**opts)
|
2014-04-30 23:52:05 +04:00
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
|
|
|
|
class PasswordResetConfirmSerializer(serializers.Serializer):
|
2014-04-30 23:52:05 +04:00
|
|
|
"""
|
|
|
|
Serializer for requesting a password reset e-mail.
|
|
|
|
"""
|
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
new_password1 = serializers.CharField(max_length=128)
|
|
|
|
new_password2 = serializers.CharField(max_length=128)
|
|
|
|
|
|
|
|
uid = serializers.CharField(required=True)
|
|
|
|
token = serializers.CharField(required=True)
|
|
|
|
|
|
|
|
set_password_form_class = SetPasswordForm
|
|
|
|
|
|
|
|
def custom_validation(self, attrs):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def validate(self, attrs):
|
|
|
|
self._errors = {}
|
2015-11-19 11:38:57 +03:00
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
# Decode the uidb64 to uid to get User object
|
|
|
|
try:
|
2015-11-19 11:38:57 +03:00
|
|
|
uid = force_text(uid_decoder(attrs['uid']))
|
2014-10-07 17:08:08 +04:00
|
|
|
self.user = UserModel._default_manager.get(pk=uid)
|
|
|
|
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
|
2015-01-27 18:52:54 +03:00
|
|
|
raise ValidationError({'uid': ['Invalid value']})
|
2014-10-07 17:08:08 +04:00
|
|
|
|
|
|
|
self.custom_validation(attrs)
|
|
|
|
# Construct SetPasswordForm instance
|
2015-04-28 11:22:08 +03:00
|
|
|
self.set_password_form = self.set_password_form_class(
|
|
|
|
user=self.user, data=attrs
|
|
|
|
)
|
2014-10-07 17:08:08 +04:00
|
|
|
if not self.set_password_form.is_valid():
|
2015-04-27 18:06:48 +03:00
|
|
|
raise serializers.ValidationError(self.set_password_form.errors)
|
2014-10-07 17:08:08 +04:00
|
|
|
if not default_token_generator.check_token(self.user, attrs['token']):
|
2015-01-27 18:52:54 +03:00
|
|
|
raise ValidationError({'token': ['Invalid value']})
|
2014-10-07 17:08:08 +04:00
|
|
|
|
2015-01-09 14:05:14 +03:00
|
|
|
return attrs
|
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
def save(self):
|
|
|
|
self.set_password_form.save()
|
|
|
|
|
|
|
|
|
|
|
|
class PasswordChangeSerializer(serializers.Serializer):
|
|
|
|
|
2014-11-12 13:51:22 +03:00
|
|
|
old_password = serializers.CharField(max_length=128)
|
2014-10-07 17:08:08 +04:00
|
|
|
new_password1 = serializers.CharField(max_length=128)
|
|
|
|
new_password2 = serializers.CharField(max_length=128)
|
|
|
|
|
|
|
|
set_password_form_class = SetPasswordForm
|
|
|
|
|
2014-11-12 13:51:22 +03:00
|
|
|
def __init__(self, *args, **kwargs):
|
2015-04-28 11:22:08 +03:00
|
|
|
self.old_password_field_enabled = getattr(
|
|
|
|
settings, 'OLD_PASSWORD_FIELD_ENABLED', False
|
|
|
|
)
|
2015-10-18 07:20:50 +03:00
|
|
|
self.logout_on_password_change = getattr(
|
|
|
|
settings, 'LOGOUT_ON_PASSWORD_CHANGE', False
|
|
|
|
)
|
2014-11-12 13:51:22 +03:00
|
|
|
super(PasswordChangeSerializer, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
if not self.old_password_field_enabled:
|
|
|
|
self.fields.pop('old_password')
|
|
|
|
|
|
|
|
self.request = self.context.get('request')
|
2014-11-14 12:31:02 +03:00
|
|
|
self.user = getattr(self.request, 'user', None)
|
2014-11-12 13:51:22 +03:00
|
|
|
|
2015-01-09 14:05:14 +03:00
|
|
|
def validate_old_password(self, value):
|
2015-04-28 11:22:08 +03:00
|
|
|
invalid_password_conditions = (
|
|
|
|
self.old_password_field_enabled,
|
|
|
|
self.user,
|
|
|
|
not self.user.check_password(value)
|
|
|
|
)
|
|
|
|
|
|
|
|
if all(invalid_password_conditions):
|
2014-11-12 13:51:22 +03:00
|
|
|
raise serializers.ValidationError('Invalid password')
|
2015-01-09 14:05:14 +03:00
|
|
|
return value
|
2014-11-12 13:51:22 +03:00
|
|
|
|
2014-10-07 17:08:08 +04:00
|
|
|
def validate(self, attrs):
|
2015-04-28 11:22:08 +03:00
|
|
|
self.set_password_form = self.set_password_form_class(
|
|
|
|
user=self.user, data=attrs
|
|
|
|
)
|
2014-10-07 17:08:08 +04:00
|
|
|
|
|
|
|
if not self.set_password_form.is_valid():
|
2015-01-09 14:05:14 +03:00
|
|
|
raise serializers.ValidationError(self.set_password_form.errors)
|
2014-10-07 17:08:08 +04:00
|
|
|
return attrs
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
self.set_password_form.save()
|
2015-11-19 11:38:57 +03:00
|
|
|
if not self.logout_on_password_change:
|
2015-10-19 11:12:25 +03:00
|
|
|
from django.contrib.auth import update_session_auth_hash
|
2015-10-18 07:20:50 +03:00
|
|
|
update_session_auth_hash(self.request, self.user)
|