diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/PasswordItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/PasswordItem.php index 6a8a8a2..1df00cb 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/PasswordItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/PasswordItem.php @@ -40,18 +40,13 @@ public function preSave() { $entity = $this->getEntity(); - // Skip if the password is pre hashed. This is set when migrating users from - // Drupal 7. - if (!$this->pre_hashed) { - // Update the user password for a new user or if the password has changed. - if ($entity->isNew() || - (strlen(trim($this->value)) > 0 && $this->value != $entity->original->{$this->getFieldDefinition()->getName()}->value)) { - // Allow alternate password hashing schemes. - $this->value = \Drupal::service('password')->hash(trim($this->value)); - // Abort if the hashing failed and returned FALSE. - if (!$this->value) { - throw new EntityMalformedException('The entity does not have a password.'); - } + // Update the user password if it has changed. + if ($entity->isNew() || (strlen(trim($this->value)) > 0 && $this->value != $entity->original->{$this->getFieldDefinition()->getName()}->value)) { + // Allow alternate password hashing schemes. + $this->value = \Drupal::service('password')->hash(trim($this->value)); + // Abort if the hashing failed and returned FALSE. + if (!$this->value) { + throw new EntityMalformedException('The entity does not have a password.'); } } diff --git a/core/modules/user/src/MigratePassword.php b/core/modules/user/src/MigratePassword.php index 4116c16..c541d5f 100644 --- a/core/modules/user/src/MigratePassword.php +++ b/core/modules/user/src/MigratePassword.php @@ -21,7 +21,15 @@ class MigratePassword implements PasswordInterface { /** * Indicates if MD5 password prefixing is enabled. */ - protected $enabled = FALSE; + protected $md5Prefixing = FALSE; + + /** + * Indicates if password needs hashing. + * + * Setting to false allows passwords that have already been hashed to be + * migrated. + */ + protected $needsHashing = TRUE; /** * Builds the replacement password service class. @@ -51,11 +59,16 @@ public function needsRehash($hash) { * {@inheritdoc} */ public function hash($password) { - $hash = $this->originalPassword->hash($password); + if ($this->needsHashing) { + $hash = $this->originalPassword->hash($password); + } + else { + $hash = $password; + } // Allow prefixing only if the service was asked to prefix. Check also if // the $password pattern is conforming to a MD5 result. - if ($this->enabled && preg_match('/^[0-9a-f]{32}$/', $password)) { + if ($this->md5Prefixing && preg_match('/^[0-9a-f]{32}$/', $password)) { $hash = 'U' . $hash; } @@ -66,14 +79,40 @@ public function hash($password) { * Enables the MD5 password prefixing. */ public function enableMd5Prefixing() { - $this->enabled = TRUE; + $this->md5Prefixing = TRUE; } /** * Disables the MD5 password prefixing. */ public function disableMd5Prefixing() { - $this->enabled = FALSE; + $this->md5Prefixing = FALSE; + } + + /** + * Enables hashing of passwords. + * + * @return $this + * + * @see \Drupal\user\MigratePassword::disableHashing() + */ + public function enableHashing() { + $this->needsHashing = TRUE; + return $this; + } + + /** + * Disables hashing of passwords. + * + * This is useful if passwords have already been hashed and don't require + * hashing on save. For example, Drupal 7 passwords have already been hashed + * and do not need to be hashed again during user migration. + * + * @return $this + */ + public function disableHashing() { + $this->needsHashing = FALSE; + return $this; } /** diff --git a/core/modules/user/src/Plugin/migrate/destination/EntityUser.php b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php index 64818f1..e7405da 100644 --- a/core/modules/user/src/Plugin/migrate/destination/EntityUser.php +++ b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php @@ -3,7 +3,6 @@ namespace Drupal\user\Plugin\migrate\destination; use Drupal\Component\Utility\Unicode; -use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; @@ -26,7 +25,7 @@ class EntityUser extends EntityContentBase { /** * The password service class. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\user\MigratePassword */ protected $password; @@ -56,8 +55,9 @@ class EntityUser extends EntityContentBase { */ public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, PasswordInterface $password) { parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager); - if (isset($configuration['md5_passwords'])) { - $this->password = $password; + $this->password = $password; + if (!($this->password instanceof MigratePassword)) { + throw new MigrateException('Password service has been altered by another module, aborting.'); } } @@ -84,22 +84,25 @@ public static function create(ContainerInterface $container, array $configuratio * @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(); - } - else { - throw new MigrateException('Password service has been altered by another module, aborting.'); - } + if (isset($this->configuration['md5_passwords'])) { + $this->password->enableMd5Prefixing(); } + else { + $this->password->disableHashing(); + } + // Do not overwrite the root account password. if ($row->getDestinationProperty('uid') == 1) { $row->removeDestinationProperty('pass'); } $ids = parent::import($row, $old_destination_id_values); - if ($this->password) { + + if (isset($this->configuration['md5_passwords'])) { $this->password->disableMd5Prefixing(); } + else { + $this->password->enableHashing(); + } return $ids; } @@ -107,17 +110,6 @@ public function import(Row $row, array $old_destination_id_values = array()) { /** * {@inheritdoc} */ - protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) { - if (!$this->password) { - // Tell the PasswordItem field not to re-hash the password. - $entity->pass->pre_hashed = TRUE; - } - return parent::save($entity, $old_destination_id_values); - } - - /** - * {@inheritdoc} - */ protected function processStubRow(Row $row) { parent::processStubRow($row); // Email address is not defined as required in the base field definition but