📜 ⬆️ ⬇️

Why can't I reset my password?

Such a question came today in tech support. The user enters the password recovery page, enters his email, presses the “Recover” button. The system happily reports that email has been sent. The user enters the mailbox, the user does not see the letter, the user is not satisfied.

The following is the standard: “Check that the email is entered correctly, make sure that the letter does not fall into spam”. Checked-made sure did not help. I went to the mail server - the letter was not even sent.

Break away from all cases and throw in testing. I go to the recovery page, enter my email - everything is in order, a letter with a link to password recovery comes. I enter the user's email - silence. The letter is not sent. In the log - nothing (from the word "absolutely").

This is followed by half an hour of useless throwing, a bit of bewilderment and a lot of obscene language. Calm down, take a deep breath and climb into the Django source code.
')
Password reset is responsible for resetting the password:
Hidden text
@csrf_protect def password_reset(request, is_admin_site=False, template_name='registration/password_reset_form.html', email_template_name='registration/password_reset_email.html', subject_template_name='registration/password_reset_subject.txt', password_reset_form=PasswordResetForm, token_generator=default_token_generator, post_reset_redirect=None, from_email=None, current_app=None, extra_context=None): if post_reset_redirect is None: post_reset_redirect = reverse('password_reset_done') else: post_reset_redirect = resolve_url(post_reset_redirect) if request.method == "POST": form = password_reset_form(request.POST) if form.is_valid(): opts = { 'use_https': request.is_secure(), 'token_generator': token_generator, 'from_email': from_email, 'email_template_name': email_template_name, 'subject_template_name': subject_template_name, 'request': request, } if is_admin_site: opts = dict(opts, domain_override=request.get_host()) form.save(**opts) return HttpResponseRedirect(post_reset_redirect) else: form = password_reset_form() context = { 'form': form, } if extra_context is not None: context.update(extra_context) return TemplateResponse(request, template_name, context, current_app=current_app) 


Once redirected to post_reset_redirect, it means that form.save () is executed. We look at what's under the hood:
Hidden text
 def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt', email_template_name='registration/password_reset_email.html', use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Generates a one-use only link for resetting password and sends to the user. """ from django.core.mail import send_mail UserModel = get_user_model() email = self.cleaned_data["email"] active_users = UserModel._default_manager.filter( email__iexact=email, is_active=True) for user in active_users: # Make sure that no email is sent to a user that actually has # a password marked as unusable if not user.has_usable_password(): continue if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override c = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', } subject = loader.render_to_string(subject_template_name, c) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) email = loader.render_to_string(email_template_name, c) send_mail(subject, email, from_email, [user.email]) 


Here, of course, comes to me. The user is first registered through VKontakte. Then put the email. And untied Vkontakte. And in the process of registration through VK to him, i.e. the user was assigned set_unusable_password() (for he did not have a password).

This whole stream of emotions was caused by these lines:

 # Make sure that no email is sent to a user that actually has # a password marked as unusable if not user.has_usable_password(): continue 

What for? Why? Who is guilty? Why can't I reset my password if it was not originally set? And most importantly, why is the system not reporting this in any way, but, chuckling, it redirects to post_reset_redirect ?! As it says, “explicit is better than implicit”?

In general, keep in mind. And do not step on this rake.

Update:

Thank you comrade zzeus :
Users flagged with an unusable password (see if you’re using an LDAP.) no mail will be sent either.

Well, in this regard, a small survey, I wonder.

Source: https://habr.com/ru/post/237701/


All Articles