Problem/Motivation
Users without email address cannot use reset password when not logged in.
If an anonymous user visits /user/password and enters a username of the account without email address, the form submit throws an error:
TypeError: Drupal\Core\Mail\Plugin\Mail\PhpMail::doMail(): Argument #1 ($to) must be of type string, null given, called in /core/lib/Drupal/Core/Mail/Plugin/Mail/PhpMail.php on line 136 in Drupal\Core\Mail\Plugin\Mail\PhpMail->doMail() (line 168 of /core/lib/Drupal/Core/Mail/Plugin/Mail/PhpMail.php).
Drupal\Core\Mail\Plugin\Mail\PhpMail->mail(Array) (Line: 308)
Drupal\Core\Mail\MailManager->doMail('user', 'password_reset', NULL, 'en', Array, 'xxx', 1) (Line: 181)
Drupal\Core\Mail\MailManager->Drupal\Core\Mail\{closure}() (Line: 593)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 180)
Drupal\Core\Mail\MailManager->mail('user', 'password_reset', NULL, 'en', Array, 'xxx') (Line: 952)
_user_mail_notify('password_reset', Object) (Line: 199)
Drupal\user\Form\UserPasswordForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 105)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 43)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 589)
Drupal\Core\Form\FormBuilder->processForm('user_pass', Array, Object) (Line: 321)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 593)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 183)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 50)
Drupal\ban\BanMiddleware->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
Steps to reproduce
Create a user without email address
As an anonymous user, try to submit a UserPasswordForm on /user/password for that username
Proposed resolution
Fix the condition, so that there is no error and an existing generic message
If %identifier is a valid account, an email will be sent with instructions to reset your password. is displayed.
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #21 | After.png | 18.52 KB | jatingupta40 |
| #21 | Before.png | 96.74 KB | jatingupta40 |
| #21 | TestuserProfile.png | 38.6 KB | jatingupta40 |
| #12 | after-3481894.png | 215.94 KB | asawari |
| #12 | before-3481894.png | 216.12 KB | asawari |
Issue fork drupal-3481894
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
poker10 commentedComment #3
gaurav gupta commentedComment #4
gaurav gupta commentedHello @poker10
i have gone through the issue and were able to reproduce it
but i think it would be better if we "add a form validation message, to check existence of email for a valid username" instead of showing the existing generic message.
My solution is to add a validation UserPasswordForm.php
I think it will be a good approach since it is breaking the drupal site instead of any security issues of what we see here
https://www.drupal.org/project/drupal/issues/1521996
Comment #5
zartab farooquee commentedPrevent Users Without Email Addresses from Using the Password Reset Form
You can implement a check in the password reset form handler (UserPasswordForm) to ensure that only users with a valid email address can submit the form.
Modify the submitForm() function in a custom module or use a hook, like hook_form_alter() or hook_form_user_pass_alter(), to check for the presence of an email address associated with the username.
Comment #6
poker10 commented@gaurav gupta I was thinking about keeping the UI message the same, even if the username does not have an email associated, exactly because of this information disclosure issue: #1521996: Password reset form reveals whether an email or username is in use. If we change the error message for this case, it will be possible to use this for username enumeration (especially on sites where email addresses are not required/used). I do not think that is a good idea.
I suggest to keep the behavior the same as now, so everytime the form is submitted, the same message is printed and only add another condition/or change existing conditions to handle the case a username does not have an email address.
@zartab farooquee We cannot block the form submit, since this issue is about anonymous users doing password resets. So we will know if the entered username has email address only after the form is submitted.
The similar issue is here, which is for logged in users: #3383647: Accounts without an email address will display a warning message when resetting their password on the edit page
Thanks!
Comment #7
cilefen commentedComment #9
gaurav gupta commentedComment #10
vinai_katiyar commentedComment #11
vinai_katiyar commentedchecked the MR - https://git.drupalcode.org/project/drupal/-/merge_requests/10051 and it's worked for me.
Comment #12
asawari commentedTest steps-
- Create a user without email address
- Go to reset passwords page
- submit the form
- observe the error
Test status - Fail
Patch applied successfully.
Issue still persists.
Please refer the screenshots in the attachments.
before-3481894.png
after-3481894.png
Comment #13
smustgrave commentedMR does not match the proposed solution.
That set I don't think just putting an empty check is correct, where's the backtrace to make sure we aren't hiding a larger issue.
Comment #14
poker10 commentedI am not sure what we need to add to the issue summary, but agree that the MR should be updated - at least we need another elseif in the existing condition, so that we do not end up with
Password reset form was submitted with an unknown or inactive account: %name.when actually the account exists, it just does not have an email set. So I think we should move the check to a new elseif with a new separate watchdog message, so that is clear, that a form was submitted for an account without email address. The printed message seems to be correct then, and it is as proposed in IS.Probably we should also add a simple test for this behavior as well? Something like - create user without email, log out and try to send the password for that username. I do not think we are hiding a larger issue here, simply the PhpMail does not expect to get a NULL email (which is a case, if a user account does not have an email set).
Thanks!
Comment #15
gaurav gupta commentedAdded the tests and provided the suggested changes.
Please review.
Comment #16
smustgrave commentedLeft comments on MR.
Comment #17
poker10 commentedI think there is nothing special required for the use-case mentioned in the IS, so it seems like that if we fix this this directly in the
_user_mail_notify()(see #3518058: _user_mail_notify() doesn't handle accounts without an email address), no other changes will be needed here.Comment #19
jan kellermann commentedRead patch incorrectly. Sorry, my mistake. Comment deleted.
Comment #21
jatingupta40 commentedHello @poker10,
I have updated the code as per the requirement. Now if the user having the email field empty and tries to do 'reset password', the proposed output -
If %identifier is a valid account, an email will be sent with instructions to reset your password.is displayed.User Profile -

Before -

After -

Comment #22
jatingupta40 commentedComment #23
divyansh.gupta commentedTested the latest changes and checked that the fix handles the issue as expected. There are no errors thrown, and the behavior aligns with the discussion in the issue summary. The test coverage looks good too. Thus marking this as RTBC.
Comment #24
dcam commentedThe inherent bug of
_user_mail_notify()sending emails to accounts without addresses was fixed by #3518058: _user_mail_notify() doesn't handle accounts without an email address. I'm setting the status to Needs Work so someone can determine whether additional action needs to be taken for the password reset form specifically. Note that #3518058 did not result in any user-facing messages being displayed with regard to the success or failure of emails being sent. This issue may want to take that further.