Skip to content

Commit

Permalink
Fix allauth reset password bug (#276)
Browse files Browse the repository at this point in the history
* Fix allauth reset password bug

* Fix allauth uid Invalid value

Fix allauth verify url not match

Fix unit test: test_password_reset_with_invalid_email
  • Loading branch information
LanceMoe committed Jul 2, 2021
1 parent 7368dee commit 82bd8b1
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 14 deletions.
64 changes: 64 additions & 0 deletions dj_rest_auth/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse

if 'allauth' in settings.INSTALLED_APPS:
from allauth.account import app_settings
from allauth.account.adapter import get_adapter
from allauth.account.forms import \
ResetPasswordForm as DefaultPasswordResetForm
from allauth.account.forms import default_token_generator
from allauth.account.utils import (filter_users_by_email,
user_pk_to_url_str, user_username)
from allauth.utils import build_absolute_uri
else:
from django.contrib.auth.forms import DefaultPasswordResetForm
from django.contrib.auth.tokens import default_token_generator

class PasswordResetForm(DefaultPasswordResetForm):
def clean_email(self):
"""
Invalid email should not raise error, as this would leak users
for unit test: test_password_reset_with_invalid_email
"""
email = self.cleaned_data["email"]
email = get_adapter().clean_email(email)
self.users = filter_users_by_email(email, is_active=True)
return self.cleaned_data["email"]

def save(self, request, **kwargs):
if 'allauth' not in settings.INSTALLED_APPS:
return super().save(request, **kwargs)
# for allauth
current_site = get_current_site(request)
email = self.cleaned_data['email']
token_generator = kwargs.get('token_generator', default_token_generator)

for user in self.users:

temp_key = token_generator.make_token(user)

# save it to the password reset model
# password_reset = PasswordReset(user=user, temp_key=temp_key)
# password_reset.save()

# send the password reset email
path = reverse(
'password_reset_confirm',
args=[user_pk_to_url_str(user), temp_key],
)
url = build_absolute_uri(request, path)

context = {
'current_site': current_site,
'user': user,
'password_reset_url': url,
'request': request,
}
if app_settings.AUTHENTICATION_METHOD != app_settings.AuthenticationMethod.EMAIL:
context['username'] = user_username(user)
get_adapter(request).send_mail(
'account/email/password_reset_key', email, context
)
return self.cleaned_data['email']
25 changes: 11 additions & 14 deletions dj_rest_auth/serializers.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
from django.conf import settings
from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm

from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import SetPasswordForm
from django.urls import exceptions as url_exceptions

from django.utils.encoding import force_str
from django.utils.module_loading import import_string

try:
from django.utils.translation import gettext_lazy as _
except ImportError:
from django.utils.translation import gettext_lazy as _
from rest_framework import exceptions, serializers
from rest_framework.exceptions import ValidationError

if 'allauth' in settings.INSTALLED_APPS:
from allauth.account.forms import default_token_generator
from allauth.account.utils import url_str_to_user_pk as uid_decoder
else:
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode as uid_decoder

from rest_framework import exceptions, serializers
from rest_framework.exceptions import ValidationError
try:
from django.utils.translation import gettext_lazy as _
except ImportError:
from django.utils.translation import gettext_lazy as _

from .forms import PasswordResetForm
from .models import TokenModel

# Get the UserModel
UserModel = get_user_model()


class LoginSerializer(serializers.Serializer):
username = serializers.CharField(required=False, allow_blank=True)
email = serializers.EmailField(required=False, allow_blank=True)
Expand Down Expand Up @@ -256,6 +252,7 @@ def save(self):
'use_https': request.is_secure(),
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
'request': request,
'token_generator': default_token_generator,
}

opts.update(self.get_email_options())
Expand All @@ -282,7 +279,7 @@ def custom_validation(self, attrs):

def validate(self, attrs):

# Decode the uidb64 to uid to get User object
# Decode the uidb64 (allauth use base36) to uid to get User object
try:
uid = force_str(uid_decoder(attrs['uid']))
self.user = UserModel._default_manager.get(pk=uid)
Expand Down

0 comments on commit 82bd8b1

Please sign in to comment.