Comments

Hi, khurram. Welcome to the Backdrop forum!

That's an unusual problem that hasn't been reported before. Can you provide more information? Did the upgrade happen without errors or warnings? Can you check the Backdrop "Recent log messages" under "Reports"? Are you using any contrib module related to users and passwords? (You can copy/paste the list of contrib modules by going to Reports > Debug information).

I had a similar problem with an D7 site I was upgrading to Backdrop, but mine related to inability to log in (to the D7 site) on my local lando dev site. I could log in on the public site but not on the dev site. It turned out to be an issue with the ssl setup. 

Khurrum - is your problem just on a public site and not differences between a dev and a public site?

OK i will try with a fresh install of Drupal up-gradation to Backdrop without any contributed module.

Thanks for responding!

Backdrop CMS corrupting password at first login

I've had this issue too. It mostly appeared to rear its ugly head when migrating (after running update.php) from a Drupal 7 site with quite a lot of modules. I could mitigate it by, in a first step, disallow the module entity_plus from being enabled.

But once it still happened once I moved the long converted site to a different domain, for deployment.

So this is a serious issue that could happen at any time.

Diagnose

When you just migrated a site and you log in for the first time, the system checks if the hashing of the password is strong enough. If it decides that the hashing needs to be stronger,  it grabs the opportunity to hash the password again now it knows the password as plain text. This is where it goes wrong, as apparently Backdrop may create a corrupt hashed password, and save it,  and you can not use this password to log in again after that.

My simple emergency fix was to disable the check for rehashing, by hacking the function  user_needs_new_hash to always return false.

But I've had the problem also when an administrator changes the password for another user. I just could not log in as that user using this new password.

The weird thing is that even if  the pass field is restored in the users table to what it was before the migration, I still couldn't log in with it. I suspect there might be a cache somewhere so that the database field isn't actually used...?

Hypothesis

Here's what I think what is happening.  user_save($account) may occasionally be called multiple times in one single session, hashing the already hashed password again, rendering it completely unusable to log in again.

Analysis

In user.entity.inc the function preSave hashes the password if it's not already hashed. The check if it's the case is very dubious: it checks if the field original exists in $account, which is supposedly the data as stored in the database, and sees if $account->pass is the same as $account->original->pass. This is the code from preSave:

   if ($entity->isNew() || !is_null($new_pass) && $new_pass !== $entity->original->pass) {
     // Allow alternate password hashing schemes.
     require_once BACKDROP_ROOT . '/' . settings_get('password_inc', 'core/includes/password.inc');
     $entity->pass = user_hash_password($new_pass);
     // Abort if the hashing failed and returned FALSE.
     if (!$entity->pass) {
       throw new EntityMalformedException('The entity does not have a password.');
     }
   }

If pass was hashed just earlier, then these fields will definitely be different so preSave hashes the already hashed password again.

Proposed remedies

I can think of a few ways to fix this.

  1. Replace $account->original->pass with the newly hashed  password. Since $account->original ought to represent  the data as it is in the database, I don't like this approach too much, it might one day ne used in other places to check which columns in the data need to be updated in the database. At least I think that's the idea behind this shadow  copy.
    Perhaps this might be done in postSave, which also exists...? Oh, postSave compares these two fields once again, so they shouldn't yet be the same at that exact  time.
  2. Store the newly hashed password in a new field, e..g. pass_hashed, and  if it exists, (also) compare passto this field, and if they are the same, don't rehash.
  3. Use a separate field for pass in the database and the password field for the form, e.g. pass_plain. Hash the value in pass_plain, store it in pass. No more rehashing more than once.