Problem/Motivation

If a user with a blocked account tries to reset a password, this will fail with the error message

Sorry, %name is not recognized as a username or an email address.

But if they think - OK my account has gone I'll create a new one they will get the message

The username %name is already taken.
The email address %email is already taken.

Currently this is misleading for the user.

Proposed resolution

We need to first check if the user is actually blocked or active. Then we display a more accurate message describing the current user's status instead of making the user assume their account does not exist.

Remaining tasks

User interface changes

Message when blocked accounts cannot request a new password:
"%name is blocked or has not been activated yet"

API changes

None.

CommentFileSizeAuthor
#75 after-patch.png6.05 KBAsha Nair
#75 before-patch.png5.81 KBAsha Nair
#72 interdiff_61-72.txt2.39 KBpoker10
#72 753898-72.patch2.37 KBpoker10
#72 753898-72_test-only.patch959 bytespoker10
#6 user_blocked_patch.patch1.42 KBcorbacho
#7 different_messages_for_blocked_users.patch1.77 KBopdavies
#5 user_blocked_patch.txt1.42 KBcorbacho
#10 different_messages_for_blocked_users.patch1.79 KBopdavies
#12 user_blocked_message.patch1.34 KBcorbacho
#13 blocked.patch1.34 KBcorbacho
#15 user_blocked_message.patch1.32 KBcorbacho
#18 user_blocked_message-753898-15-D7.patch1.32 KBweri
#20 user_blocked_message-753898-16-D7.patch1.24 KBweri
#22 user_blocked_message-753898-22-D7.patch1.15 KBweri
#27 753898-27.fail_.patch1.3 KBidebr
#27 753898-27.patch2.86 KBidebr
#34 drupal-753898-34.patch2.88 KBdscl
#42 drupal-753898-42.patch2.87 KBdscl
#46 interdiff.txt591 byteswillzyx
#46 drupal-753898-46.patch2.87 KBwillzyx
#47 blocked_user.png47.55 KBmanauwarsheikh
#52 753898-52.patch2.25 KBSivaji_Ganesh_Jojodae
#54 753898-54.patch2.11 KBSivaji_Ganesh_Jojodae
#57 Reset Passowrd - Before Patch.jpg69.2 KBNikitaJain
#57 Create account with existing email-id : Before patch.jpg81.12 KBNikitaJain
#57 Message if user blocked- After patch.jpg68.06 KBNikitaJain
#60 wrong_message_for-753898-60.patch2.46 KBtalhaparacha
#61 wrong_message_for-753898-61.patch2.46 KBtalhaparacha
#66 Error message on reset password - Before applying patch.jpg66.45 KBNikitaJain
#66 Create a new account with existing email-id-Before patch.jpg87.3 KBNikitaJain
#66 Error on applying the patch.jpg41.31 KBNikitaJain
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

opdavies’s picture

I've added some additional code to the user_pass_validate function to account for blocked users, and to display a different error message. The updated function is:

function user_pass_validate($form, &$form_state) {
  $name = trim($form_state['values']['name']);
  
  // Blocked accounts cannot request a new password,
  // check provided username and email against access rules.
  if (drupal_is_denied('user', $name) || drupal_is_denied('mail', $name)) {
    form_set_error('name', t('%name is not allowed to request a new password.', array('%name' => $name)));
  }

  // Try to load by email.
  $account = user_load(array('mail' => $name, 'status' => 1));
  if (!$account) {
    // No success, try to load by name.
    $account = user_load(array('name' => $name, 'status' => 1));
  }

  $name = $form_state['values']['name'];
  // Check if the account name exists, and if the account status is '0'
  if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE name = '%s';", $name)) && $account->status == 0) {
    form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $name)));
  }
  
  if (isset($account->uid)) {
    form_set_value(array('#parents' => array('account')), $account, $form_state);
  }
    
  else {
    form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name)));
  }
}
Rhino’s picture

Thank you! I was just wondering how to make a better message for blocked accounts! Perfect.

opdavies’s picture

No problem! :)

silverwing’s picture

Is this something that can be added to D7 (or D8)?

corbacho’s picture

FileSize
1.42 KB

This was fixed in D6. See https://drupal.org/node/332703

And in Drupal 7 the account is loaded with the new function user_load_multiple with the condition status = 1 (not load the user if it's blocked). But with this approach, there is no good way to know the reason of why is not being loaded.

In the patch attached...

I removed the condition 'status' => '1' so we can set a suitable message, checking the status.

Surprisingly, even in the database the status is '1' (blocked), after being loaded with user_load_multiple, it says '0' (non blocked). I will confirm later again and open a issue in that case.

corbacho’s picture

Version: 6.x-dev » 7.x-dev
Status: Active » Needs review
FileSize
1.42 KB

now with correct extension .patch

opdavies’s picture

Attached is a patch that includes my code above. :)

Status: Needs review » Needs work

The last submitted patch, different_messages_for_blocked_users.patch, failed testing.

opdavies’s picture

Status: Needs work » Needs review
opdavies’s picture

Updated patch.

Status: Needs review » Needs work

The last submitted patch, different_messages_for_blocked_users.patch, failed testing.

corbacho’s picture

FileSize
1.34 KB

Hi Opdavies.

I'm a newbie on submitting patches, but if am not wrong, you are trying to submit patches against Drupal 6.

I moved the thread to Drupal-7 version, where is the problem now. Because in Drupal 6 this problem has been *fixed* (I think since 6.16) (see this for more http://drupal.org/node/332703).

So let's try to fix this for Drupal 7. What do you think folks about this:

Sorry, the username %name has not been activated yet or is blocked
Or you prefer to stick with Drupal 6 message
'%name is not allowed to request a new password.'

Here is a correct patch. Forget about what I said about the "status" bug, I mixed the status 0 and 1. 0 is blocked, 1 active :)

corbacho’s picture

FileSize
1.34 KB

Hmmm... Why is Ignored? extension was right..
Trying to rename the patch file name and indicating the path for the file
cvs diff -up modules/user/user.pages.inc > blocked.patch

yoroy’s picture

Status: Needs work » Needs review

Well thank you for taking the time to start writing patches! Set status to 'needs review' to summon the test bot :-)

We had an epic patch weeks ago that removed all instances of 'Please' in the interface text. Let's not add to the 'Sorry's' here :) Drupal tone of voice wants to focus on short and simple but not casual or anthropomorphized. Nevertheless, the new message is more concrete and gives more hints to what might be wrong in a particular case. Propose:

%name is blocked or has not been activated yet.

corbacho’s picture

FileSize
1.32 KB

hehehe.. yes I like more your propose, thanks yoroy !

opdavies’s picture

Hi corbacho,

I didn't realise that this issue had been moved into the Drupal 7 queue. I was starting to wonder why my patch kept failing. :)

Ollie.

corbacho’s picture

np

#12 and #13 are identical patches. First failed, the other passed. Did I miss something?

weri’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
FileSize
1.32 KB

I think it's important to differ the message for non existing and blocked user.

I tested (Drupal 7.34) and reviewed the patch #15 and think its ready to commit. Patch on comment #18 is the same as #15, I just changed the patch name.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 18: user_blocked_message-753898-15-D7.patch, failed testing.

weri’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
1.24 KB

Reroll the patch.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: user_blocked_message-753898-16-D7.patch, failed testing.

weri’s picture

Retest the patch.

weri’s picture

Status: Needs work » Reviewed & tested by the community
corbacho’s picture

Version: 7.x-dev » 8.1.x-dev
Status: Reviewed & tested by the community » Needs work

Thanks weri for bringing back this issue after 4 years.

I don't know if bug still persists in D8.

In that case, first needs to be fixed in Drupal 8.1.x (Drupal 8.0.x translatable strings are already frozen), and maybe then, backported to D7.

David_Rothstein’s picture

Version: 8.1.x-dev » 8.0.x-dev
Issue tags: +Needs backport to D7

That link says strings are unfrozen, not frozen. They are frozen after the first release candidate.

It does seem likely that this exists in Drupal 8 also because there is similar code in UserPasswordForm::validateForm().

I wonder if this behavior is somewhat intentional though? Maybe we don't want to inform the whole world that a particular user has been blocked from the site... On the other hand it's quite possible there are already other ways to find that out.

idebr’s picture

In the current state it is already possible to see an account has been blocked by the exact same mechanic: the email address is already registered, but unable to request a new password. Might as well update the status message accordingly then :)

idebr’s picture

Status: Needs work » Needs review
FileSize
1.3 KB
2.86 KB

The issue still occurs in 8.0.x. I ported the patch and added a test. Strangely enough, there was no test yet to check if a blocked user can request a password.

The last submitted patch, 27: 753898-27.fail_.patch, failed testing.

dscl’s picture

Status: Needs review » Reviewed & tested by the community

I'm at DrupalCon LA sprints and we are working on this issue.

dscl’s picture

Status: Reviewed & tested by the community » Needs review
dscl’s picture

Status: Needs review » Reviewed & tested by the community

We've just successfully applied the last patch on latest 8.0.x-dev code, tested and it worked for us.
Moving it to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 27: 753898-27.patch, failed testing.

Anonymous’s picture

I am currently updating the Issue Summary.

dscl’s picture

Status: Needs work » Needs review
FileSize
2.88 KB

Updated patch to meet the new changes to 8.0.x-dev.

Status: Needs review » Needs work

The last submitted patch, 34: drupal-753898-34.patch, failed testing.

Anonymous’s picture

Issue summary: View changes
Anonymous’s picture

Issue summary: View changes

Status: Needs work » Needs review

opdavies queued 34: drupal-753898-34.patch for re-testing.

opdavies’s picture

Status: Needs review » Needs work

The patch seems to apply locally. Re-queuing the test.

The last submitted patch, 34: drupal-753898-34.patch, failed testing.

opdavies’s picture

Tests are failing at Drupal\user\Tests\UserPasswordResetTest->testUserPasswordReset() are failing, on lines 161 and 162 in UserPasswordResetTest.php.

dscl’s picture

FileSize
2.87 KB

Updated the test so it post the form accordingly.

dscl’s picture

Status: Needs work » Needs review
Anonymous’s picture

Status: Needs review » Reviewed & tested by the community

Just tested this and it works for me. RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/user/src/Form/UserPasswordForm.php
@@ -116,14 +116,20 @@ public function buildForm(array $form, FormStateInterface $form_state) {
+      if ($account->isBlocked()) {

I think this should be !$account->isActive() that way we're maintaining the same logic as previously which would have ignored users where status equalled anything other than 1.

willzyx’s picture

Status: Needs work » Needs review
FileSize
591 bytes
2.87 KB

as for #45

manauwarsheikh’s picture

FileSize
47.55 KB

Verified! seems fine to me.
When a user is blocked then message "The username manauwar has not been activated or is blocked." will appear.
I have checked for different cases.
a. When blocked user is trying to login.
b. When blocked user enter wrong inputs.
c. When blocked user is trying to "request password/reset password".
Screenshot attached.

manauwarsheikh’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +#SrijanSprintDay
xjm’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

I think this makes sense. Thanks all for the work on this issue!

I think this should be !$account->isActive() that way we're maintaining the same logic as previously which would have ignored users where status equalled anything other than 1.

Nice catch!

As a usability improvement, this issue is a prioritized change as per https://www.drupal.org/core/beta-changes and its benefits outweigh any disruption. Committed and pushed to 8.0.x. Thanks!

Moving to 7.x for backport.

  • xjm committed 9cdd22c on 8.0.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...
opdavies’s picture

Version: 8.0.x-dev » 7.x-dev
Sivaji_Ganesh_Jojodae’s picture

Status: Patch (to be ported) » Needs review
FileSize
2.25 KB

Patch #22 re-rolled. Reused the status message used for login for validation. Also added a test case but it is failing in my local.

Status: Needs review » Needs work

The last submitted patch, 52: 753898-52.patch, failed testing.

Sivaji_Ganesh_Jojodae’s picture

Status: Needs work » Needs review
FileSize
2.11 KB

Vamsi krishna queued 52: 753898-52.patch for re-testing.

The last submitted patch, 52: 753898-52.patch, failed testing.

NikitaJain’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
69.2 KB
81.12 KB
68.06 KB

Tested the above patch patches/753898-54.patch. Its working fine. Manually verified if the user is blocked & try to reset the password the error message appears as "Sorry, %name is not recognized as a username or an email address".
- If user try to create a new account with same username or email-id error message appears as "The username %name is already taken.
The email address %email is already taken".

After applying the patch:
- If user try to reset the password for blocked account:
""The username %email has not been activated or is blocked"

Its working as expected. Screenshots attached.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work
  1. +  if ($account){
    +    // Blocked accounts cannot request a new password,
    +    // check provided username and email against access rules.
    +    if ($account->status == 0) {
    +      form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $name)));
    +    }
    +  }
       if (isset($account->uid)) {
         form_set_value(array('#parents' => array('account')), $account, $form_state);
       }
    

    I think we need to be a little more careful here. Especially since this is a form that is frequently altered, we should preserve the behavior where form_set_value() only gets called if the account is valid and the password reset email is actually going to be sent. Otherwise $form_state['values']['account'] could get set when it's not valid, and that could mess with other validation handlers.

    So basically the new code should not be its own check that runs in addition to the form_set_value(), but rather inside the isset($account->uid) so it runs as an alternative to it.

  2. +  if ($account){
    

    (minor) There should be a space after the closing parenthesis.

  3. +    // Blocked accounts cannot request a new password,
    +    // check provided username and email against access rules.
    

    I'm not sure what the second sentence means here - should it just be removed?

  4. +      form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $name)));
    

    I like that this is reusing an existing translatable string (so it doesn't break translations) but unfortunately "username" isn't really correct here since it can also be an email address.

    Maybe if we go ahead with this issue, we'll just have to live with that, though.

  5. +    // Confirm the password reset.
    +    $this->assertNoText(t('Further instructions have been sent to your e-mail address.'));
    

    Shouldn't we also be asserting that the expected message is shown? Perhaps we can borrow more from the committed Drupal 8 patch here?

  • xjm committed 9cdd22c on 8.1.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...
talhaparacha’s picture

Status: Needs work » Needs review
FileSize
2.46 KB

Backported to D7. Applied all changes suggested at #58 to the patch at #54

talhaparacha’s picture

  • xjm committed 9cdd22c on 8.3.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...

  • xjm committed 9cdd22c on 8.3.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...

  • xjm committed 9cdd22c on 8.4.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...

  • xjm committed 9cdd22c on 8.4.x
    Issue #753898 by corbacho, weri, opdavies, dscl, idebr, willzyx,...
NikitaJain’s picture

Verified and tested on the latest 8.4.x-dev version. Its working fine as per the description added on top.
Here are the test observations:
Without applying any patch on 8.4.x-dev :
1. If user try to reset the password for blocked account the error message appears as:
""The username %email has not been activated or is blocked"
2. If user try to create a new account with same username or email-id error message appears as
"The username %name is already taken.
The email address %email is already taken".
Screenshots attached

- Moving it to RTBC as the issue is already fixed on latest version 8.4.x-dev.

NikitaJain’s picture

dscl’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: -Needs backport to D7

Hey NikitaJain,

Thanks for your work on this!

I'm moving this back to Needs Review because this issue was already fixed on 8.0.x and it becomes part to the new releases/branches automatically.

What we need now is to get the D7 backport reviewed and tested so it can get pushed to the latest 7.x.

Cheers!

The last submitted patch, 61: wrong_message_for-753898-61.patch, failed testing.

opdavies’s picture

Patch in #61 applies cleanly to the latest 7.x branch.

Going to do some manual testing and check the testbot failure.

David_Rothstein’s picture

+      form_set_error('name', t('The account %name has not been activated or is blocked.', array('%name' => $name)));

Like I said in point 4 of #58 it is probably better to use the text that the previous patch had, even though it's slightly inaccurate (since it's text that is already translated elsewhere in Drupal). This is an important error message and it would be bad to display it in English to users who don't speak that language.

+    //Blocked accounts cannot request a new password.
+    if($account->status == 0) {
+      form_set_error('name', t('The account %name has not been activated or is blocked.', array('%name' => $name)));
+    }
+    else {
+    form_set_value(array('#parents' => array('account')), $account,
+      $form_state);
+    }

There are still minor coding standards issues here - need a space after the //, a space after the if, the form_set_value line should be indented by two spaces (since it's inside the else {}), and I don't think there's any reason to split the form_set_value onto multiple lines.

The last submitted patch, 72: 753898-72_test-only.patch, failed testing. View results

Asha Nair’s picture

Applied #72 patch successfully in D7

Asha Nair’s picture

FileSize
5.81 KB
6.05 KB
Asha Nair’s picture

poker10’s picture

Issue tags: +Needs change record

This would need a change record for D7.

mcdruid’s picture

Status: Needs review » Needs work

I think we probably want to change the message text based on #3200198: [D7] password reset form prevent revealing email or username in use.

poker10’s picture

Ah, I see that, thanks! It seems like that not all changes were backported from the original D9 issue (#1521996) in the issue you are referencing.

In the D9 issue this was removed too (so that no specific message is output in this case):

-      // Blocked accounts cannot request a new password.
-      if (!$account->isActive()) {
-        $form_state->setErrorByName('name', $this->t('%name is blocked or has not been activated yet.', ['%name' => $name]));
-      }

But it was not backported, because D7 is already loading only active accounts. See:

  // Try to load by email.
  $users = user_load_multiple(array(), array('mail' => $name, 'status' => '1'));
  $account = reset($users);
  if (!$account) {
    // No success, try to load by name.
    $users = user_load_multiple(array(), array('name' => $name, 'status' => '1'));
    $account = reset($users);
  }
  if (isset($account->uid)) {
  ...
  }

Looking at that, this seems that we do not need to do any changes in D7 anymore, because the process is now working correctly (it was fixed by #3200198: [D7] password reset form prevent revealing email or username in use).

1 - If you request a password for non-existing account, you will get "If %identifier is a valid account, an email will be sent with instructions to reset your password."

2 - If you request a password for a blocked account, you will get the same message, because no account will be loaded either.

If I have not missed anything, this could be closed as Fixed in D8 and thats all.

mcdruid’s picture

Status: Needs work » Closed (works as designed)
Issue tags: -Needs change record

Yeah that makes sense - I agree we can close this for D7 as the correct non-specific message is displayed.

Thank you everyone for all the work that went into it.

poker10’s picture

Version: 7.x-dev » 8.4.x-dev
Status: Closed (works as designed) » Fixed

As this was a D8/D7 mixed issue and it was committed to D8, it is probably better to close this as Fixed (for D8), so that people get credits for that D8 patch finally.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.