From 2a35762338da2709f1813bf7677d59ab8c253f7a Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 3 May 2021 17:26:49 +0200 Subject: [PATCH] fix: deprecated code paths on Symfony 5.3 --- phpstan.neon.dist | 3 ++ tests/Behat/DoctrineContext.php | 11 +++--- tests/Fixtures/TestBundle/Document/User.php | 6 ++-- tests/Fixtures/TestBundle/Entity/User.php | 6 ++-- .../Security/AbstractSecurityUser.php | 34 +++++++++++++++++++ tests/Fixtures/app/AppKernel.php | 7 ++-- 6 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 tests/Fixtures/TestBundle/Security/AbstractSecurityUser.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f9a17a2f633..7ce4570a647 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -35,6 +35,7 @@ parameters: - tests/Bridge/Symfony/Bundle/Test/WebTestCaseTest.php - tests/ProphecyTrait.php - tests/Behat/CoverageContext.php + - tests/Fixtures/TestBundle/Security/AbstractSecurityUser.php earlyTerminatingMethodCalls: PHPUnit\Framework\Constraint\Constraint: - fail @@ -89,6 +90,8 @@ parameters: # Expected, Symfony 5.3 - '#getCollectionValueT|getCollectionKeyTyp#' + - '#isPasswordValid#' + - '#UserPasswordHasherInterface#' # Expected, due to PHP 8 attributes - '#ReflectionProperty::getAttributes\(\)#' diff --git a/tests/Behat/DoctrineContext.php b/tests/Behat/DoctrineContext.php index 4625095f016..59494073f22 100644 --- a/tests/Behat/DoctrineContext.php +++ b/tests/Behat/DoctrineContext.php @@ -169,6 +169,7 @@ use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; use Ramsey\Uuid\Uuid; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Uid\Uuid as SymfonyUuid; @@ -182,7 +183,7 @@ final class DoctrineContext implements Context */ private $manager; private $doctrine; - private $passwordEncoder; + private $passwordHasher; private $schemaTool; private $schemaManager; @@ -192,11 +193,13 @@ final class DoctrineContext implements Context * Every scenario gets its own context instance. * You can also pass arbitrary arguments to the * context constructor through behat.yml. + * + * @param UserPasswordEncoderInterface|UserPasswordHasherInterface $passwordHasher */ - public function __construct(ManagerRegistry $doctrine, UserPasswordEncoderInterface $passwordEncoder) + public function __construct(ManagerRegistry $doctrine, $passwordHasher) { $this->doctrine = $doctrine; - $this->passwordEncoder = $passwordEncoder; + $this->passwordHasher = $passwordHasher; $this->manager = $doctrine->getManager(); $this->schemaTool = $this->manager instanceof EntityManagerInterface ? new SchemaTool($this->manager) : null; $this->schemaManager = $this->manager instanceof DocumentManager ? $this->manager->getSchemaManager() : null; @@ -1198,7 +1201,7 @@ public function thereIsAUrlEncodedIdResource() public function thePasswordForUserShouldBeHashed(string $password, string $user) { $user = $this->doctrine->getRepository($this->isOrm() ? User::class : UserDocument::class)->find($user); - if (!$this->passwordEncoder->isPasswordValid($user, $password)) { + if (!$this->passwordHasher->isPasswordValid($user, $password)) { throw new \Exception('User password mismatch'); } } diff --git a/tests/Fixtures/TestBundle/Document/User.php b/tests/Fixtures/TestBundle/Document/User.php index 34e04a79762..4a19447c268 100644 --- a/tests/Fixtures/TestBundle/Document/User.php +++ b/tests/Fixtures/TestBundle/Document/User.php @@ -18,8 +18,8 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\PasswordResetRequestResult; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordInput; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordOutput; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Security\AbstractSecurityUser; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; -use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\Annotation\Groups; /** @@ -58,7 +58,7 @@ * @author Théo FIDRY * @author Kévin Dunglas */ -class User implements UserInterface +class User extends AbstractSecurityUser { /** * @var int @@ -156,7 +156,7 @@ public function getRoles(): array return ['ROLE_USER']; } - public function getPassword() + public function getPassword(): ?string { return null; } diff --git a/tests/Fixtures/TestBundle/Entity/User.php b/tests/Fixtures/TestBundle/Entity/User.php index 37653366199..616b9d4a8d0 100644 --- a/tests/Fixtures/TestBundle/Entity/User.php +++ b/tests/Fixtures/TestBundle/Entity/User.php @@ -18,8 +18,8 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\PasswordResetRequestResult; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordInput; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordOutput; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Security\AbstractSecurityUser; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\Annotation\Groups; /** @@ -59,7 +59,7 @@ * @author Théo FIDRY * @author Kévin Dunglas */ -class User implements UserInterface +class User extends AbstractSecurityUser { /** * @var int @@ -159,7 +159,7 @@ public function getRoles(): array return ['ROLE_USER']; } - public function getPassword() + public function getPassword(): ?string { return null; } diff --git a/tests/Fixtures/TestBundle/Security/AbstractSecurityUser.php b/tests/Fixtures/TestBundle/Security/AbstractSecurityUser.php new file mode 100644 index 00000000000..5a649689fbb --- /dev/null +++ b/tests/Fixtures/TestBundle/Security/AbstractSecurityUser.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Security; + +use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; +use Symfony\Component\Security\Core\User\UserInterface; + +// Forward compatibility layer for symfony/password-hasher:^5.3 +if (interface_exists(PasswordAuthenticatedUserInterface::class)) { + abstract class AbstractSecurityUser implements UserInterface, PasswordAuthenticatedUserInterface + { + abstract public function getPassword(): ?string; + + public function getUserIdentifier(): string + { + return $this->getUsername(); + } + } +} else { + abstract class AbstractSecurityUser implements UserInterface + { + } +} diff --git a/tests/Fixtures/app/AppKernel.php b/tests/Fixtures/app/AppKernel.php index 1fe07564e33..161600e7380 100644 --- a/tests/Fixtures/app/AppKernel.php +++ b/tests/Fixtures/app/AppKernel.php @@ -12,6 +12,7 @@ declare(strict_types=1); use ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle; +use ApiPlatform\Core\Tests\Behat\DoctrineContext; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\User as UserDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User; use ApiPlatform\Core\Tests\Fixtures\TestBundle\TestBundle; @@ -117,6 +118,8 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load $loader->load(__DIR__.'/config/config_symfony_uid.yml'); } + $c->getDefinition(DoctrineContext::class)->setArgument('$passwordHasher', class_exists(NativePasswordHasher::class) ? 'security.user_password_encoder' : 'security.user_password_hasher'); + $c->prependExtensionConfig('framework', [ 'secret' => 'dunglas.fr', 'validation' => ['enable_annotations' => true], @@ -136,9 +139,9 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load 'router' => ['utf8' => true], ]); - $alg = class_exists(NativePasswordHasher::class) || class_exists('Symfony\Component\Security\Core\Encoder\NativePasswordEncoder') ? 'auto' : 'bcrypt'; + $alg = class_exists(NativePasswordHasher::class, false) || class_exists('Symfony\Component\Security\Core\Encoder\NativePasswordEncoder') ? 'auto' : 'bcrypt'; $securityConfig = [ - 'encoders' => [ + class_exists(NativePasswordHasher::class) ? 'password_hashers' : 'encoders' => [ User::class => $alg, UserDocument::class => $alg, // Don't use plaintext in production!