Issue #3238227 by alexpott: \Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem causes deprecation errors on PHP 8.1

merge-requests/1256/head
catch 2021-09-27 13:21:54 +01:00
parent f680e8ea6c
commit b6e74cf3fb
3 changed files with 204 additions and 7 deletions

View File

@ -523,6 +523,16 @@ field.value.string_long:
type: text
label: 'Value'
# Schema for the configuration of the Password field type.
field.storage_settings.password:
type: field.storage_settings.string
label: 'Password settings'
field.field_settings.password:
type: mapping
label: 'Password settings'
# Schema for the configuration of the URI field type.
field.storage_settings.uri:

View File

@ -46,6 +46,11 @@ class PasswordItem extends StringItem {
// Reset the pre_hashed value since it has now been used.
$this->pre_hashed = FALSE;
}
elseif (!$entity->isNew() && empty($this->value)) {
// If the password is empty, that means it was not changed, so use the
// original password.
$this->value = $entity->original->{$this->getFieldDefinition()->getName()}->value;
}
elseif ($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));
@ -55,13 +60,6 @@ class PasswordItem extends StringItem {
}
}
if (!$entity->isNew()) {
// If the password is empty, that means it was not changed, so use the
// original password.
if (empty($this->value)) {
$this->value = $entity->original->{$this->getFieldDefinition()->getName()}->value;
}
}
// Ensure that the existing password is unset to minimise risks of it
// getting serialized and stored somewhere.
$this->existing = NULL;

View File

@ -0,0 +1,189 @@
<?php
namespace Drupal\KernelTests\Core\Field\FieldType;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Password\PasswordInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\field\Kernel\FieldKernelTestBase;
/**
* @coversDefaultClass \Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem
* @group Field
*/
class PasswordItemTest extends FieldKernelTestBase {
/**
* A field storage to use in this test class.
*
* @var \Drupal\field\Entity\FieldStorageConfig
*/
protected $fieldStorage;
/**
* The field used in this test class.
*
* @var \Drupal\field\Entity\FieldConfig
*/
protected $field;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->fieldStorage = FieldStorageConfig::create([
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'type' => 'password',
]);
$this->fieldStorage->save();
$this->field = FieldConfig::create([
'field_storage' => $this->fieldStorage,
'bundle' => 'entity_test',
'required' => TRUE,
]);
$this->field->save();
}
/**
* @covers ::preSave
*/
public function testPreSavePreHashed() {
$entity = EntityTest::create([
'name' => $this->randomString(),
]);
$entity->test_field = 'this_is_not_a_real_hash';
$entity->test_field->pre_hashed = TRUE;
$entity->save();
$this->assertSame('this_is_not_a_real_hash', $entity->test_field->value);
$this->assertFalse($entity->test_field->pre_hashed);
}
/**
* @covers ::preSave
*/
public function testPreSaveNewNull() {
$entity = EntityTest::create([
'name' => $this->randomString(),
]);
$entity->test_field = NULL;
$entity->save();
$this->assertNull($entity->test_field->value);
}
/**
* @covers ::preSave
*/
public function testPreSaveNewEmptyString() {
$entity = EntityTest::create([
'name' => $this->randomString(),
]);
$entity->test_field = '';
$entity->save();
// The string starts with the portable password string and is a hash of an
// empty string.
$this->assertStringStartsWith('$S$', $entity->test_field->value);
$this->assertTrue($this->container->get('password')->check('', $entity->test_field->value));
}
/**
* @covers ::preSave
*/
public function testPreSaveNewMultipleSpacesString() {
$entity = EntityTest::create([
'name' => $this->randomString(),
]);
$entity->test_field = ' ';
$entity->save();
// The string starts with the portable password string and is a hash of an
// empty string.
$this->assertStringStartsWith('$S$', $entity->test_field->value);
$this->assertTrue($this->container->get('password')->check('', $entity->test_field->value));
}
/**
* @covers ::preSave
*/
public function testPreSaveExistingNull() {
$entity = EntityTest::create();
$entity->test_field = $this->randomString();
$entity->save();
$this->assertNotNull($entity->test_field->value);
$entity->test_field = NULL;
$entity->save();
$this->assertNull($entity->test_field->value);
}
/**
* @covers ::preSave
*/
public function testPreSaveExistingEmptyString() {
$entity = EntityTest::create();
$entity->test_field = $this->randomString();
$entity->save();
$hashed_password = $entity->test_field->value;
$entity->test_field = '';
$entity->save();
$this->assertSame($hashed_password, $entity->test_field->value);
}
/**
* @covers ::preSave
*/
public function testPreSaveExistingMultipleSpacesString() {
$entity = EntityTest::create();
$entity->test_field = $this->randomString();
$entity->save();
$entity->test_field = ' ';
$entity->save();
// @todo Fix this bug in https://www.drupal.org/project/i/3238399.
$this->assertSame(' ', $entity->test_field->value);
}
/**
* @covers ::preSave
*/
public function testPreSaveExceptionNew() {
$entity = EntityTest::create();
$entity->test_field = str_repeat('a', PasswordInterface::PASSWORD_MAX_LENGTH + 1);
$this->expectException(EntityStorageException::class);
$this->expectExceptionMessage('The entity does not have a password');
$entity->save();
}
/**
* @covers ::preSave
*/
public function testPreSaveExceptionExisting() {
$entity = EntityTest::create();
$entity->test_field = 'will_be_hashed';
$entity->save();
$this->assertNotEquals('will_be_hashed', $entity->test_field->value);
$this->expectException(EntityStorageException::class);
$this->expectExceptionMessage('The entity does not have a password');
$entity->test_field = str_repeat('a', PasswordInterface::PASSWORD_MAX_LENGTH + 1);
$entity->save();
}
}