diff --git a/core/lib/Drupal/Core/Password/PhpPassword.php b/core/lib/Drupal/Core/Password/PhpPassword.php index a26b8e4..3e02b8f 100644 --- a/core/lib/Drupal/Core/Password/PhpPassword.php +++ b/core/lib/Drupal/Core/Password/PhpPassword.php @@ -13,7 +13,14 @@ * Secure password hashing functions based on PHP (>=5.5.0) password hashing * functions. * + * NOTE: Because password hashing functions are available only since PHP 5.5, on + * PHP 5.4 the compatibility is assured by the 'password_compat' library (see + * https://github.com/ircmaxell/password_compat). + * * @see http://php.net/manual/en/ref.password.php + * @see https://github.com/ircmaxell/password_compat + * + * @todo Remove 'password_compat' library when Drupal will require PHP >= 5.5.0 */ class PhpPassword implements PasswordInterface { @@ -67,7 +74,7 @@ public function check($password, UserInterface $account) { $stored_hash = substr($stored_hash, 2); $password = $this->drupal7Password->hash($password); } - // Password migrated from Drupal 6. + // MD5 migrated password (Drupal 6). elseif (substr($stored_hash, 0, 2) == 'U$') { $stored_hash = substr($stored_hash, 1); $password = md5($password); diff --git a/core/modules/migrate/src/MigratePassword.php b/core/modules/migrate/src/MigratePassword.php index 796c7f1..2d45f41 100644 --- a/core/modules/migrate/src/MigratePassword.php +++ b/core/modules/migrate/src/MigratePassword.php @@ -8,12 +8,13 @@ namespace Drupal\migrate; use Drupal\Core\Password\PasswordInterface; +use Drupal\migrate\Entity\MigrationInterface; use Drupal\user\UserInterface; /** - * Replaces the original 'password' service in order to prefix the MD5 re-hashed - * passwords with the 'U' flag. The new salted hash is recreated on first login - * similarly to the D6->D7 upgrade path. + * Replaces the original 'password' service in order to prefix the MD5 or + * Drupal 7 re-hashed passwords. The new salted hash will be recreated on first + * login similarly to the D6->D7 upgrade path. */ class MigratePassword implements PasswordInterface { @@ -26,10 +27,19 @@ class MigratePassword implements PasswordInterface { /** * Indicates if MD5 password prefixing is enabled. + * + * @var bool */ protected $enabled = FALSE; /** + * The current migration. + * + * @var \Drupal\migrate\Entity\MigrationInterface + */ + protected $migration; + + /** * Builds the replacement password service class. * * @param \Drupal\Core\Password\PasswordInterface $original_password @@ -66,13 +76,11 @@ public function hash($password) { if (preg_match('/^[0-9a-f]{32}$/', $password)) { $hash = 'U' . $hash; } - // @todo Is this enough? Maybe we should pass and test somehow the current - // migration source to detect a Drupal 7 source. This can be done by - // injecting the current migration when enabling prefixing in - // Drupal\migrate\Plugin\migrate\destination\EntityUser. In that case - // ::enableMd5Prefixing() needs to be renamed. Or pass the migration into - // constructor? How? - if (substr($password, 0, 3) == '$S$') { + // Prefix user hashed passwords coming from Drupal 7. + // @todo This needs testing when D7->D8 migration will be merged into main + // repository. + $source = $this->migration->getSourcePlugin()->getPluginId(); + if (substr($password, 0, 3) == '$S$' && $source == 'd7_user') { $hash = 'D7' . $hash; } } @@ -81,17 +89,27 @@ public function hash($password) { } /** - * Enables the MD5 password prefixing. + * Enables password prefixing. */ - public function enableMd5Prefixing() { + public function enablePrefixing() { $this->enabled = TRUE; } /** - * Disables the MD5 password prefixing. + * Disables password prefixing. */ - public function disableMd5Prefixing() { + public function disablePrefixing() { $this->enabled = FALSE; } + /** + * Sets the current migration. + * + * @param \Drupal\migrate\Entity\MigrationInterface $migration + * The current migration. + */ + public function setMigration(MigrationInterface $migration) { + $this->migration = $migration; + } + } diff --git a/core/modules/migrate/src/MigrateServiceProvider.php b/core/modules/migrate/src/MigrateServiceProvider.php index 78a60bb..705f9d2 100644 --- a/core/modules/migrate/src/MigrateServiceProvider.php +++ b/core/modules/migrate/src/MigrateServiceProvider.php @@ -12,10 +12,10 @@ /** * Swaps the original 'password' service in order to handle password hashing for - * user migrations that have passwords hashed to MD5. + * user migrations that have passwords hashed with MD5 or Drupal 7 passwords. * * @see \Drupal\migrate\MigratePassword - * @see \Drupal\Core\Password\PhpassHashedPassword + * @see \Drupal\Core\Password\PhpPassword */ class MigrateServiceProvider implements ServiceModifierInterface { diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityUser.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityUser.php index 786988f..34fd890 100644 --- a/core/modules/migrate/src/Plugin/migrate/destination/EntityUser.php +++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityUser.php @@ -13,7 +13,6 @@ use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\MigrateException; use Drupal\migrate\MigratePassword; -use Drupal\migrate\Plugin\MigratePluginManager; use Drupal\migrate\Row; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -79,12 +78,14 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} + * * @throws \Drupal\migrate\MigrateException */ public function import(Row $row, array $old_destination_id_values = array()) { if ($this->password) { if ($this->password instanceof MigratePassword) { - $this->password->enableMd5Prefixing(); + $this->password->setMigration($this->migration); + $this->password->enablePrefixing(); } else { throw new MigrateException('Password service has been altered by another module, aborting.'); @@ -92,7 +93,7 @@ public function import(Row $row, array $old_destination_id_values = array()) { } $ids = parent::import($row, $old_destination_id_values); if ($this->password) { - $this->password->disableMd5Prefixing(); + $this->password->disablePrefixing(); } return $ids;