Migrating user password from non-drupal database to Drupal 8

Usually when a site makes the decision to migrate to a new platform, one of the challenges you may find on the new implementation is to migrate the user password without force users to change their password on the first login on the new website.

The Drupal 8 Migration API provides support for this. By default, the Migration API lets you take the MD5 passwords from the old website and re-hash it on Drupal 8. To enable it, you will need to set md5_passwords to true  on your user migration plugin:

destination:
  plugin: entity:user
  md5_passwords: true

If your old website uses a different algorithm than MD5 to hash passwords you will need to follow some additional steps in order to re-hash on the new website.

For this, we need to use a custom module to add some code (I use the name “mymodule” in my example). We define a new service to process all the submitted passwords from users by add adding a mymodule.services.yml file with the following:

services: 
  password: 
    class: Drupal\mymodule\MyPasswordHasher 
    arguments: [16]

Then, we create the class that implements the mentioned interface by creating a file on Drupal\mymodule\src\MyPasswordHasher.php

The logic to include on this class is up to you, one approach you can take is to inherit  Drupal/Core/Password/PhpassHashedPassword.php class and override the check() method.

/**
 * @file
 * Definition of Drupal\mymodule\MyPasswordHasher
 */
namespace Drupal\mymodule;

use Drupal\Component\Utility\Crypt;
use Drupal\Core\Password\PhpassHashedPassword;
use Drupal\Core\Password\PasswordInterface;

/**
 * My custom secure password hashing functions.
 */
class MyPasswordHasher extends PhpassHashedPassword implements PasswordInterface {

  /**
   * {@inheritdoc}
   */
  public function check ($password, $hash) {

    if (substr($hash, 0, 2) == 'U$') {

      $stored_hash = substr($hash, 1);
      //
      // Here you use the same algorithm the old site has to hash passwords
      // and store it on $password.

      if (substr($stored_hash, 0, 3) == '$P$') {
        // A phpass password generated using md5. This is a password migrated with
        // md5_passwords = TRUE
        $computed_hash = $this->crypt('md5', $password, $stored_hash);
        return $computed_hash && Crypt::hashEquals($stored_hash, $computed_hash);
      }
    }

    return parent::check($password, $hash);
  }
}

When user logs in on the new website, the check() method is going to do the following:

  • checks the md5_passwords mark we added on password of migrated users.
  • If submitted password has the mark, it hash it with same algorithm from old website and compare with the one stored during migration, if they are the same returns the result of $computed_hash && Crypt::hashEquals($stored_hash, $computed_hash)
  • If submitted passowrd doesn’t have the mark (users registered on D8 site), it uses logic from PhpassHashedPassword clas provided by Drupal core.

 

Hopefully, this article will give you some solutions for your migration to Drupal 8.

 

More information can be found on:

  • https://www.drupal.org/docs/8/api/migrate-api/migrate-destination-entityuser
  • https://drupal.stackexchange.com/questions/206743/how-do-i-change-hashing-algorithm

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.