When a user receives an email with a link to login, the user can enter a new password.
Immediately afterwards, the text "You have tried to use a one-time login link that has either been used or is no longer valid" appears, even though the link is brand new.
I have done several tests and got the same problem every time.
The problem has occurred within 3-4 months.
The result is that PRLP cannot be used.
---
Core: 7.79
PHP: 7.4.16
All modules: Latest version installed

Comments

Uv516 created an issue. See original summary.

uv516’s picture

Issue summary: View changes
isholgueras’s picture

I can confirm this is happening to me in a recently upgraded Drupal 7.79.

One of the things introduced in 7.79 is in user.pages.inc:148, a new session variable named $_SESSION['pass_reset_hash']

  if (isset($_SESSION['pass_reset_hash'])) {
    $session_reset_hash = $_SESSION['pass_reset_hash'];
    unset($_SESSION['pass_reset_hash']);
  }
  else {
    $session_reset_hash = NULL;
  }

And later is used to check whether the reset call is valid or not:


        if ($hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
               // Some code
        elseif ($session_reset_hash && $session_reset_hash == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
          $is_valid = TRUE;
        }
      }
      if ($is_valid) {
        // Reset code.
      else {
        drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
        drupal_goto('user/password');
      }

For some reason, $_SESSION is empty when prlp is enabled but has the right value if the module prlp is disabled.

isholgueras’s picture

Hi all,

I think I found the root issue.

In Drupal 7.79, due to this issue: https://www.drupal.org/node/3205476, a new change in user.pages.inc:251 was introduced.

$form['#action'] = url("user/reset/$uid/$timestamp/$session_reset_hash/login");

The problem comes when in prlp_form_user_pass_reset_alter we are executing unset($form['#action']);, so we're deleting the action Drupal is inserting. This causes to not even enter in the login action indeed:

// user.pages.inc:231
        if ($action == 'login') {
          // Set the new user.
          $user = $account;
          // user_login_finalize() also updates the login timestamp of the
          // user, which invalidates further use of the one-time login link.
          user_login_finalize();
          // Clear any password reset flood events for this user.
          flood_clear_event('pass_reset_user', $account->uid);
          watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
          drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
          // Let the user's password be changed without the current password check.
          $token = drupal_random_key();
          $_SESSION['pass_reset_' . $user->uid] = $token;
          drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
        }

If I remove the code of unsetting the form #action, the user is now able to log in, but the password change is not applied.

isholgueras’s picture

Status: Active » Needs review
StatusFileSize
new1.74 KB

I was able to fix the issue, but we need a change in Drupal core. Here is the ticket and patch: https://www.drupal.org/project/drupal/issues/3208600

And here is also the patch I've created. Maybe is not very clean and there is another better approach, but after the Drupal 7.79 changes, the $hashed_pass does no longer come in the form action, so I had to save it in session.

Applying both patches fixes the issue with the login, but I would like to know from the Drupal core team if I'm missing something with the change in drupal core.

mistergroove’s picture

Patch doesn't work for me. Thought it might be a result of require_login module too but disabling this still results in the same behaviour:

Password reset link clicked

Reset password form works normally but submitting it takes you to the forgotten password page with the following message:

"You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below." every time.

Password is not changed.

steveganz’s picture

@mistergroove, did you also apply the patch in https://www.drupal.org/project/drupal/issues/3208600#comment-14058941?

mistergroove’s picture

Thanks @steveganz and @isholgueras. I overlooked that patch. Works fine now.

I've added a note in the drupal 7.79 Change records for "Password reset confirmation form changes" to hopefully direct anyone else having a simular issue.

https://www.drupal.org/node/3205476#comment-14060024

Hope that was in the right place.

Thanks again.

loze’s picture

Applying both patches got this working correctly for me. Thanks!

sveldkamp’s picture

Applying both patches fixed the issue for me as well. Thank you!

eogiles’s picture

This patch and the one from the other issue seem to resolve the issue. However I did not make the first change from this patch, from lines 19-27 and do not understand the purpose of it. It appears to be adding a menu item for the user reset URL which will display the admin configuration screen? That seems odd. Am I misunderstanding, or is that a mistake?

roderik’s picture

StatusFileSize
new3.39 KB
new3.39 KB

New patch:

  • Intercepts the hash (from the session value) in drupal_goto_alter(), instead of (from the form action) in the form builder. (Edit:
    I guess this change wasn't necessary - we could keep populating $_SESSION['plrp_reset_hash'] from $form['#action']. This new patch doesn't populate $_SESSION['plrp_reset_hash'] on older Drupal versions, which I guess is a small advantage...)
  • Makes the Core patch unnecessary (by setting the hash back so the form will properly rebuild on submit).
roderik’s picture

StatusFileSize
new2.5 KB

Here's the actual patch :)

izmeez’s picture

Title: One-time login not working » One-time login not working with drupal 7.79

Updated issue title to be more explicit.

loze’s picture

Patch in #14 works and does not require the core patch. This is a better solution. +1

nullkernel’s picture

Patch #14 worked for me (after editing the prlp.module file's path in the diff). In addition to fixing password resets, it also fixed "drush user-login <username>".

I'm not sure if the "drush user-login <username>" problem happens on sites that don't have PRLP enabled. If it does, Drupal core might be the ideal place to fix this.

tomtech’s picture

StatusFileSize
new2.38 KB

As noted by @nullkernel, the patch in #3208362-14: One-time login not working with drupal 7.79 doesn't apply cleanly, as it presumes a specific project root, rather than the module root.

Attached is a re-roll done at the module root.

simgui8’s picture

#18 fixes the problem for me (tested on Drupal 7.80).

Thanks everyone!

jurgenhaas’s picture

Status: Needs review » Reviewed & tested by the community

Works great, thanks for the patch. RTBC

puddyglum’s picture

#18 kind of fixes the problem, but we're getting an error after choosing the new password:

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'zE3essVgcAQsA5sDazynWaaBaJIFrGmP968JXvPSUh0-hLAgehJJmNx_CD7SWho6' for key 'PRIMARY': UPDATE {sessions} SET sid=:db_update_placeholder_0, ssid=:db_update_placeholder_1 WHERE (ssid = :db_condition_placeholder_0) ; Array ( [:db_update_placeholder_0] => zE3essVgcAQsA5sDazynWaaBaJIFrGmP968JXvPSUh0 [:db_update_placeholder_1] => hLAgehJJmNx_CD7SWho6JtROhyGzqz4x79WVmV_b_AA [:db_condition_placeholder_0] => K8u03-2bETlZ76wt7ULfFrEiBfGepmu5wRJxo__0Ggk ) in drupal_session_regenerate() (line 431 of /var/www/drupal/includes/session.inc).

This only happens once. Subsequent attempts appear to be fine. We have replicated the error three times with different users, both in dev and prod environments.

puddyglum’s picture

This error may be unrelated to this module. We are not seeing this error on a fresh install of Drupal 7.80 with only PRLP installed patch #18.

These are the steps that recreate the issue every time in our current live site.

  1. Request a new password reset link.
  2. Copy the link.
  3. Paste the link in a new incognito window.
  4. Choose a new password and submit.
  5. Responds with an unstyled page saying that the password updated, but also the word "Error".

We disabled LoginToboggan and still see this error, so we're still hunting it down. Don't want our issue impact the release of this fix. Thought I would share in case others are experiencing this issue.

puddyglum’s picture

To resolve the SQL error for our site we needed to remove user_login_finalize() from prlp_user_pass_reset_submit(). We tested to make sure that the password reset link was still invalidated and could not be used a second time.

** Update: Removing user_login_finalize() had other consequences such as Access Denied to the destination after the user changes their via PRLP. We've spent enough time on this and have chosen to switch to Simple Password Reset to avoid this scenario entirely.

daveiano’s picture

Patch from #18 works for me. The core patch is not needed.

jitesh doshi’s picture

Hi, this is the project maintainer. @TomTech (or anyone else), can you explain why we have a situation where we can't find the hash and give out a message "Could not find password hash; login will likely fail"? Why and under what circumstances we would have such variant and unpredictable behavior?

rjenkins’s picture

Patch from #18 worked for me on D7.80. Thanks!

tomtech’s picture

HI @jitesh-doshi. I'll defer to @roderik for a definitive answer, as the patch I provided in #18 was simply a re-roll of his patch.

The code that would produce that message seems to be defensive programming to handle an edge case.

It would probably make more sense if it either:
1. Wrote to watchdog instead.
2. Displayed a more user friendly message, rather than this debugging type of message.

I can observe that I've been using this in production for 2+ weeks now, so would also echo RTBC.

  • Jitesh Doshi committed 190241a on 7.x-1.x
    Issue #3208362 by roderik, isholgueras, TomTech, Jitesh Doshi: One-time...
jitesh doshi’s picture

Status: Reviewed & tested by the community » Fixed

Patch incorporated into the repo and official release created 7.x-1.4. Thank you everyone who contributed!

mistergroove’s picture

Nice one guys. Thanks.

roderik’s picture

Thank you. In answer to #25:

can you explain why we have a situation where we can't find the hash and give out a message "Could not find password hash; login will likely fail"? Why and under what circumstances we would have such variant and unpredictable behavior?

I know of no such case; TomTech is right that it was just defensive programming - because it feels like the presence of $_SESSION can be influenced by 'whatever' outside forces. Actually... the report in #3208600-11: Newly introduced $_SESSION['pass_reset_hash'] doesn't allow to alter user_pass_reset form looks like it could encounter this situation.

Whether just a watchdog log or a better message is needed, I leave up to the module maintainers. (I don't know of a useful message to display here, so it becomes a question of: do you want the user to see something in this case, so they can report something more than "login doesn't work"?)

Status: Fixed » Closed (fixed)

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

loze’s picture

I am also getting the Integrity constraint violation error as described in #21 and #22 after setting the password using plrp 7.x-1.4 and drupal 7.81

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'at1ET7ri9-E6WVJMq5Q_kAI4QmR9CmlnHl_bIcpyYDU-czMwLmGzHmpStbEJyyqX' for key 'PRIMARY': UPDATE {sessions} SET sid=:db_update_placeholder_0, ssid=:db_update_placeholder_1 WHERE (ssid = :db_condition_placeholder_0) ; Array ( [:db_update_placeholder_0] => at1ET7ri9-E6WVJMq5Q_kAI4QmR9CmlnHl_bIcpyYDU [:db_update_placeholder_1] => czMwLmGzHmpStbEJyyqX1xvpPpkuKldJmcc0Kre1I7M [:db_condition_placeholder_0] => 5xseHqSPtEM6zFX1odylzGrLgOWMjMJMoqxlVeAtF-c ) in drupal_session_regenerate() (line 431 of C:\www\fstoppers\includes\session.inc).

q11q11’s picture

Drupal 7.80 + patch #2 from drupal.org/project/drupal/issues/3208600 + PRLP 7.x-1.4 = I'm still having
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ... for key 'PRIMARY': UPDATE {sessions} ... in drupal_session_regenerate() (line 431 of ... /includes/session.inc)

nortmas’s picture

The same issue for me - "PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry...."
Any Ideas?