Update to Drupal 8.1.5. For more information, see https://www.drupal.org/project/drupal/releases/8.1.5
This commit is contained in:
parent
13b6ca7cc2
commit
38ba7c357d
342 changed files with 7814 additions and 1534 deletions
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Password\PasswordInterface;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class MigratePassword implements PasswordInterface {
|
||||
|
||||
/**
|
||||
* The original password service.
|
||||
*
|
||||
* @var \Drupal\Core\Password\PasswordInterface
|
||||
*/
|
||||
protected $originalPassword;
|
||||
|
||||
/**
|
||||
* Indicates if MD5 password prefixing is enabled.
|
||||
*/
|
||||
protected $enabled = FALSE;
|
||||
|
||||
/**
|
||||
* Builds the replacement password service class.
|
||||
*
|
||||
* @param \Drupal\Core\Password\PasswordInterface $original_password
|
||||
* The password object.
|
||||
*/
|
||||
public function __construct(PasswordInterface $original_password) {
|
||||
$this->originalPassword = $original_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function check($password, $hash) {
|
||||
return $this->originalPassword->check($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function needsRehash($hash) {
|
||||
return $this->originalPassword->needsRehash($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hash($password) {
|
||||
$hash = $this->originalPassword->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)) {
|
||||
$hash = 'U' . $hash;
|
||||
}
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the MD5 password prefixing.
|
||||
*/
|
||||
public function enableMd5Prefixing() {
|
||||
$this->enabled = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the MD5 password prefixing.
|
||||
*/
|
||||
public function disableMd5Prefixing() {
|
||||
$this->enabled = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the PhpassHashedPassword::getCountLog2() method.
|
||||
*
|
||||
* @todo: Revisit this whole alternate password service:
|
||||
* https://www.drupal.org/node/2540594.
|
||||
*/
|
||||
public function getCountLog2($setting) {
|
||||
return $this->originalPassword->getCountLog2($setting);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,14 +3,13 @@
|
|||
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;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EmailItem;
|
||||
use Drupal\Core\Password\PasswordInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\user\MigratePassword;
|
||||
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -55,9 +54,7 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,24 +80,29 @@ class EntityUser extends EntityContentBase {
|
|||
* @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.');
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
$this->password->disableMd5Prefixing();
|
||||
}
|
||||
return parent::import($row, $old_destination_id_values);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function save(ContentEntityInterface $entity, array $old_destination_id_values = array()) {
|
||||
// Do not overwrite the root account password.
|
||||
if ($entity->id() != 1) {
|
||||
// Set the pre_hashed password so that the PasswordItem field does not hash
|
||||
// already hashed passwords. If the md5_passwords configuration option is
|
||||
// set we need to rehash the password and prefix with a U.
|
||||
// @see \Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem::preSave()
|
||||
$entity->pass->pre_hashed = TRUE;
|
||||
if (isset($this->configuration['md5_passwords'])) {
|
||||
$entity->pass->value = 'U' . $this->password->hash($entity->pass->value);
|
||||
}
|
||||
}
|
||||
return parent::save($entity, $old_destination_id_values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ class Role extends DrupalSqlBase {
|
|||
public function query() {
|
||||
$query = $this->select('role', 'r')
|
||||
->fields('r', array('rid', 'name'))
|
||||
->orderBy('rid');
|
||||
->orderBy('r.rid');
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class User extends DrupalSqlBase {
|
|||
public function query() {
|
||||
return $this->select('users', 'u')
|
||||
->fields('u', array_keys($this->baseFields()))
|
||||
->condition('uid', 0, '>');
|
||||
->condition('u.uid', 0, '>');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ class UserPicture extends DrupalSqlBase {
|
|||
$query = $this->select('users', 'u')
|
||||
->condition('picture', '', '<>')
|
||||
->fields('u', array('uid', 'access', 'picture'))
|
||||
->orderBy('access');
|
||||
->orderBy('u.access');
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class UserPictureFile extends DrupalSqlBase {
|
|||
*/
|
||||
public function query() {
|
||||
$query = $this->select('users', 'u')
|
||||
->condition('picture', '', '<>')
|
||||
->condition('u.picture', '', '<>')
|
||||
->fields('u', array('uid', 'picture'));
|
||||
return $query;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class User extends FieldableEntity {
|
|||
public function query() {
|
||||
return $this->select('users', 'u')
|
||||
->fields('u')
|
||||
->condition('uid', 0, '>');
|
||||
->condition('u.uid', 0, '>');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -163,7 +163,7 @@ class SharedTempStore {
|
|||
*
|
||||
* @return bool
|
||||
* TRUE if the data was set, or FALSE if it already exists and is not owned
|
||||
* by $this->user.
|
||||
* by $this->user.
|
||||
*/
|
||||
public function setIfOwner($key, $value) {
|
||||
if ($this->setIfNotExists($key, $value)) {
|
||||
|
|
|
@ -42,8 +42,6 @@ interface UserDataInterface {
|
|||
* The name of the data key.
|
||||
* @param mixed $value
|
||||
* The value to store. Non-scalar values are serialized automatically.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($module, $uid, $name, $value);
|
||||
|
||||
|
@ -60,8 +58,6 @@ interface UserDataInterface {
|
|||
* @param string $name
|
||||
* (optional) The name of the data key. If omitted, all data associated with
|
||||
* $module and $uid is deleted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete($module = NULL, $uid = NULL, $name = NULL);
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Swaps the original 'password' service in order to handle password hashing for
|
||||
* user migrations that have passwords hashed to MD5.
|
||||
*
|
||||
* @see \Drupal\migrate\MigratePassword
|
||||
* @see \Drupal\Core\Password\PhpassHashedPassword
|
||||
*/
|
||||
class UserServiceProvider implements ServiceModifierInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function alter(ContainerBuilder $container) {
|
||||
$container->setDefinition('password_original', $container->getDefinition('password'));
|
||||
$container->setDefinition('password', $container->getDefinition('password_migrate'));
|
||||
}
|
||||
|
||||
}
|
|
@ -44,6 +44,8 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
* The username.
|
||||
* @param string $mail
|
||||
* The user's email address.
|
||||
* @param string $password
|
||||
* The password for this user.
|
||||
* @param int $access
|
||||
* The last access time.
|
||||
* @param int $login
|
||||
|
@ -59,7 +61,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
* @param bool $has_picture
|
||||
* Whether the user is expected to have a picture attached.
|
||||
*/
|
||||
protected function assertEntity($id, $label, $mail, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE) {
|
||||
protected function assertEntity($id, $label, $mail, $password, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = User::load($id);
|
||||
$this->assertTrue($user instanceof UserInterface);
|
||||
|
@ -77,13 +79,29 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
$this->assertIdentical($init, $user->getInitialEmail());
|
||||
$this->assertIdentical($roles, $user->getRoles());
|
||||
$this->assertIdentical($has_picture, !$user->user_picture->isEmpty());
|
||||
$this->assertIdentical($password, $user->getPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 user to Drupal 8 migration.
|
||||
*/
|
||||
public function testUser() {
|
||||
$this->assertEntity(2, 'Odo', 'odo@local.host', '0', '0', FALSE, '', 'odo@local.host');
|
||||
$password = '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ';
|
||||
$this->assertEntity(2, 'Odo', 'odo@local.host', $password, '0', '0', FALSE, '', 'odo@local.host');
|
||||
|
||||
// Ensure that the user can authenticate.
|
||||
$this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
|
||||
// After authenticating the password will be rehashed because the password
|
||||
// stretching iteration count has changed from 15 in Drupal 7 to 16 in
|
||||
// Drupal 8.
|
||||
$user = User::load(2);
|
||||
$rehash = $user->getPassword();
|
||||
$this->assertNotEquals($password, $rehash);
|
||||
|
||||
// Authenticate again and there should be no re-hash.
|
||||
$this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
|
||||
$user = User::load(2);
|
||||
$this->assertEquals($rehash, $user->getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,9 +66,6 @@ services:
|
|||
arguments: ['@current_user', '@entity.manager']
|
||||
tags:
|
||||
- { name: 'context_provider' }
|
||||
password_migrate:
|
||||
class: Drupal\user\MigratePassword
|
||||
arguments: ['@password_original']
|
||||
|
||||
parameters:
|
||||
user.tempstore.expire: 604800
|
||||
|
|
Reference in a new issue