3

Django password_reset Form does not check if email exists or not. Also validates form whatever email address is given.

The question is, how do i check and throw error for non existing emails with custom form?

By the way, i found below solution at here but it is not working for me. (using Django 2.1). And if this should work, i couldn't found what i am missing.

forms.py

class EmailValidationOnForgotPassword(PasswordResetForm):
def clean_email(self):
    email = self.cleaned_data['email']
    if not User.objects.filter(email__iexact=email, is_active=True).exists():
        raise ValidationError("There is no user registered with the specified email address!")

    return email

urls.py

path('sifre-sifirla/', PasswordResetView.as_view(), {'password_reset_form':EmailValidationOnForgotPassword}, name='password_reset'),

Thank you in advance.

EDIT:

For other users information, question is answered by @Alasdair and working but @pypypy 's point of view is also important.

changes in urls.py as below:

path('sifre-sifirla/', PasswordResetView.as_view(form_class=EmailValidationOnForgotPassword), name='password_reset'),
Sarp
  • 55
  • 8
  • 1
    In general you don’t want to show an error where the email does not exist because this can be used as a user enumeration security flaw. – pypypy Oct 23 '18 at 10:59
  • Yes you are right! So, adding some information like "You would enter another email address if you didn't receive an email" on password_reset_done.html would solve the problem. By the way, i would like to know the solution for future use. Thank you anyway. @pypypy – Sarp Oct 23 '18 at 11:18
  • 1
    For the `PasswordResetView`, the attribute is `form_class` instead of `password_reset_form`. I would remove the dictionary and pass it as an argument to `as_view()`: `path('sifre-sifirla/', PasswordResetView.as_view(form_class=EmailValidationOnForgotPassword), name='password_reset'),`. – Alasdair Oct 23 '18 at 12:26
  • 1
    @Alasdair , thank you for this reply and it is working now. But also pypypy 's point view is also important for me. Now i have clue for how to do. Thanks again. – Sarp Oct 25 '18 at 09:42
  • Yes, you want to consider whether or not it is acceptable to reveal that an account exists. But remember, you may already reveal it in other places. For example, your registration page might give an error "An account with that email already exists". – Alasdair Oct 25 '18 at 10:09
  • @Alasdair exactly the best place to use. – Sarp Oct 31 '18 at 08:42

1 Answers1

1

Summarizing the discussion above with parts taken from @Alasdair

#forms.py
from django.contrib.auth.forms import PasswordResetForm

class EmailValidationOnForgotPassword(PasswordResetForm):

    def clean_email(self):
        email = self.cleaned_data['email']
        if not User.objects.filter(email__iexact=email, is_active=True).exists():
            msg = _("There is no user registered with the specified E-Mail address.")
            self.add_error('email', msg)
        return email

And

#urls.py
from accounts.forms import EmailValidationOnForgotPassword

path('sifre-sifirla/', PasswordResetView.as_view(form_class=EmailValidationOnForgotPassword), name='password_reset'),

@pypypy, is correct in saying that this approach can be used to obtain usernames. One way to reduce this issue is to respond with a 429 Too Many Requests as soon an user tries 3 different E-Mails. That can be achived using for example django-ratelimit

ohlr
  • 1,839
  • 1
  • 13
  • 29