diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index f87e606c3a4e1..8801866969723 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -5,6 +5,12 @@ CHANGELOG --- * The `security.authorization_checker` and `security.token_storage` services are now private + * Remove `UserPasswordEncoderCommand` class and the corresponding `user:encode-password` command, + use `UserPasswordHashCommand` and `user:hash-password` instead + * Remove the `security.encoder_factory.generic` service, the `security.encoder_factory` and `Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface` aliases, + use `security.password_hasher_factory` and `Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface` instead + * Remove the `security.user_password_encoder.generic` service, the `security.password_encoder` and the `Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface` aliases, + use `security.user_password_hasher`, `security.password_hasher` and `Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface` instead 5.3 --- diff --git a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php deleted file mode 100644 index 09f4df8d2165a..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php +++ /dev/null @@ -1,216 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\SecurityBundle\Command; - -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\Question; -use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\PasswordHasher\Command\UserPasswordHashCommand; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; -use Symfony\Component\Security\Core\Encoder\SelfSaltingEncoderInterface; - -/** - * Encode a user's password. - * - * @author Sarah Khalil - * - * @final - * - * @deprecated since Symfony 5.3, use {@link UserPasswordHashCommand} instead - */ -class UserPasswordEncoderCommand extends Command -{ - protected static $defaultName = 'security:encode-password'; - protected static $defaultDescription = 'Encode a password'; - - private $encoderFactory; - private $userClasses; - - public function __construct(EncoderFactoryInterface $encoderFactory, array $userClasses = []) - { - $this->encoderFactory = $encoderFactory; - $this->userClasses = $userClasses; - - parent::__construct(); - } - - /** - * {@inheritdoc} - */ - protected function configure() - { - $this - ->setDescription(self::$defaultDescription) - ->addArgument('password', InputArgument::OPTIONAL, 'The plain password to encode.') - ->addArgument('user-class', InputArgument::OPTIONAL, 'The User entity class path associated with the encoder used to encode the password.') - ->addOption('empty-salt', null, InputOption::VALUE_NONE, 'Do not generate a salt or let the encoder generate one.') - ->setHelp(<<%command.name% command encodes passwords according to your -security configuration. This command is mainly used to generate passwords for -the in_memory user provider type and for changing passwords -in the database while developing the application. - -Suppose that you have the following security configuration in your application: - - -# app/config/security.yml -security: - encoders: - Symfony\Component\Security\Core\User\InMemoryUser: plaintext - App\Entity\User: auto - - -If you execute the command non-interactively, the first available configured -user class under the security.encoders key is used and a random salt is -generated to encode the password: - - php %command.full_name% --no-interaction [password] - -Pass the full user class path as the second argument to encode passwords for -your own entities: - - php %command.full_name% --no-interaction [password] 'App\Entity\User' - -Executing the command interactively allows you to generate a random salt for -encoding the password: - - php %command.full_name% [password] 'App\Entity\User' - -In case your encoder doesn't require a salt, add the empty-salt option: - - php %command.full_name% --empty-salt [password] 'App\Entity\User' - -EOF - ) - ; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $errorIo = $output instanceof ConsoleOutputInterface ? new SymfonyStyle($input, $output->getErrorOutput()) : $io; - - $errorIo->caution('The use of the "security:encode-password" command is deprecated since version 5.3 and will be removed in 6.0. Use "security:hash-password" instead.'); - - $input->isInteractive() ? $errorIo->title('Symfony Password Encoder Utility') : $errorIo->newLine(); - - $password = $input->getArgument('password'); - $userClass = $this->getUserClass($input, $io); - $emptySalt = $input->getOption('empty-salt'); - - $encoder = $this->encoderFactory->getEncoder($userClass); - $saltlessWithoutEmptySalt = !$emptySalt && $encoder instanceof SelfSaltingEncoderInterface; - - if ($saltlessWithoutEmptySalt) { - $emptySalt = true; - } - - if (!$password) { - if (!$input->isInteractive()) { - $errorIo->error('The password must not be empty.'); - - return 1; - } - $passwordQuestion = $this->createPasswordQuestion(); - $password = $errorIo->askQuestion($passwordQuestion); - } - - $salt = null; - - if ($input->isInteractive() && !$emptySalt) { - $emptySalt = true; - - $errorIo->note('The command will take care of generating a salt for you. Be aware that some encoders advise to let them generate their own salt. If you\'re using one of those encoders, please answer \'no\' to the question below. '.\PHP_EOL.'Provide the \'empty-salt\' option in order to let the encoder handle the generation itself.'); - - if ($errorIo->confirm('Confirm salt generation ?')) { - $salt = $this->generateSalt(); - $emptySalt = false; - } - } elseif (!$emptySalt) { - $salt = $this->generateSalt(); - } - - $encodedPassword = $encoder->encodePassword($password, $salt); - - $rows = [ - ['Encoder used', \get_class($encoder)], - ['Encoded password', $encodedPassword], - ]; - if (!$emptySalt) { - $rows[] = ['Generated salt', $salt]; - } - $io->table(['Key', 'Value'], $rows); - - if (!$emptySalt) { - $errorIo->note(sprintf('Make sure that your salt storage field fits the salt length: %s chars', \strlen($salt))); - } elseif ($saltlessWithoutEmptySalt) { - $errorIo->note('Self-salting encoder used: the encoder generated its own built-in salt.'); - } - - $errorIo->success('Password encoding succeeded'); - - return 0; - } - - /** - * Create the password question to ask the user for the password to be encoded. - */ - private function createPasswordQuestion(): Question - { - $passwordQuestion = new Question('Type in your password to be encoded'); - - return $passwordQuestion->setValidator(function ($value) { - if ('' === trim($value)) { - throw new InvalidArgumentException('The password must not be empty.'); - } - - return $value; - })->setHidden(true)->setMaxAttempts(20); - } - - private function generateSalt(): string - { - return base64_encode(random_bytes(30)); - } - - private function getUserClass(InputInterface $input, SymfonyStyle $io): string - { - if (null !== $userClass = $input->getArgument('user-class')) { - return $userClass; - } - - if (empty($this->userClasses)) { - throw new RuntimeException('There are no configured encoders for the "security" extension.'); - } - - if (!$input->isInteractive() || 1 === \count($this->userClasses)) { - return reset($this->userClasses); - } - - $userClasses = $this->userClasses; - natcasesort($userClasses); - $userClasses = array_values($userClasses); - - return $io->choice('For which user class would you like to encode a password?', $userClasses, reset($userClasses)); - } -} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 942e27d7ec109..ea219217ca9c2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -66,23 +66,6 @@ public function getConfigTreeBuilder() return $v; }) ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { - if ($v['encoders'] ?? false) { - trigger_deprecation('symfony/security-bundle', '5.3', 'The child node "encoders" at path "security" is deprecated, use "password_hashers" instead.'); - - return true; - } - - return $v['password_hashers'] ?? false; - }) - ->then(function ($v) { - $v['password_hashers'] = array_merge($v['password_hashers'] ?? [], $v['encoders'] ?? []); - $v['encoders'] = $v['password_hashers']; - - return $v; - }) - ->end() ->children() ->scalarNode('access_denied_url')->defaultNull()->example('/foo/error403')->end() ->enumNode('session_fixation_strategy') @@ -111,7 +94,6 @@ public function getConfigTreeBuilder() ->end() ; - $this->addEncodersSection($rootNode); $this->addPasswordHashersSection($rootNode); $this->addProvidersSection($rootNode); $this->addFirewallsSection($rootNode, $this->factories); @@ -392,58 +374,6 @@ private function addProvidersSection(ArrayNodeDefinition $rootNode) ; } - private function addEncodersSection(ArrayNodeDefinition $rootNode) - { - $rootNode - ->fixXmlConfig('encoder') - ->children() - ->arrayNode('encoders') - ->example([ - 'App\Entity\User1' => 'auto', - 'App\Entity\User2' => [ - 'algorithm' => 'auto', - 'time_cost' => 8, - 'cost' => 13, - ], - ]) - ->requiresAtLeastOneElement() - ->useAttributeAsKey('class') - ->prototype('array') - ->canBeUnset() - ->performNoDeepMerging() - ->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end() - ->children() - ->scalarNode('algorithm') - ->cannotBeEmpty() - ->validate() - ->ifTrue(function ($v) { return !\is_string($v); }) - ->thenInvalid('You must provide a string value.') - ->end() - ->end() - ->arrayNode('migrate_from') - ->prototype('scalar')->end() - ->beforeNormalization()->castToArray()->end() - ->end() - ->scalarNode('hash_algorithm')->info('Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms.')->defaultValue('sha512')->end() - ->scalarNode('key_length')->defaultValue(40)->end() - ->booleanNode('ignore_case')->defaultFalse()->end() - ->booleanNode('encode_as_base64')->defaultTrue()->end() - ->scalarNode('iterations')->defaultValue(5000)->end() - ->integerNode('cost') - ->min(4) - ->max(31) - ->defaultNull() - ->end() - ->scalarNode('memory_cost')->defaultNull()->end() - ->scalarNode('time_cost')->defaultNull()->end() - ->scalarNode('id')->end() - ->end() - ->end() - ->end() - ->end() - ; - } - private function addPasswordHashersSection(ArrayNodeDefinition $rootNode) { $rootNode diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 0d9fbc6ec4f46..1b8827c046be3 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -40,8 +40,6 @@ use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher; use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; use Symfony\Component\Security\Core\User\ChainUserProvider; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -184,11 +182,6 @@ public function load(array $configs, ContainerBuilder $container) $container->getDefinition('security.authentication.guard_handler') ->replaceArgument(2, $this->statelessFirewallKeys); - // @deprecated since Symfony 5.3 - if ($config['encoders']) { - $this->createEncoders($config['encoders'], $container); - } - if ($config['password_hashers']) { $this->createHashers($config['password_hashers'], $container); } @@ -196,9 +189,6 @@ public function load(array $configs, ContainerBuilder $container) if (class_exists(Application::class)) { $loader->load('console.php'); - // @deprecated since Symfony 5.3 - $container->getDefinition('security.command.user_password_encoder')->replaceArgument(1, array_keys($config['encoders'])); - $container->getDefinition('security.command.user_password_hash')->replaceArgument(1, array_keys($config['password_hashers'])); } @@ -680,120 +670,6 @@ private function getUserProvider(ContainerBuilder $container, string $id, array throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "%s" listener on "%s" firewall is ambiguous as there is more than one registered provider.', $factoryKey, $id)); } - private function createEncoders(array $encoders, ContainerBuilder $container) - { - $encoderMap = []; - foreach ($encoders as $class => $encoder) { - if (class_exists($class) && !is_a($class, PasswordAuthenticatedUserInterface::class, true)) { - trigger_deprecation('symfony/security-bundle', '5.3', 'Configuring an encoder for a user class that does not implement "%s" is deprecated, class "%s" should implement it.', PasswordAuthenticatedUserInterface::class, $class); - } - $encoderMap[$class] = $this->createEncoder($encoder); - } - - $container - ->getDefinition('security.encoder_factory.generic') - ->setArguments([$encoderMap]) - ; - } - - private function createEncoder(array $config) - { - // a custom encoder service - if (isset($config['id'])) { - return new Reference($config['id']); - } - - if ($config['migrate_from'] ?? false) { - return $config; - } - - // plaintext encoder - if ('plaintext' === $config['algorithm']) { - $arguments = [$config['ignore_case']]; - - return [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => $arguments, - ]; - } - - // pbkdf2 encoder - if ('pbkdf2' === $config['algorithm']) { - return [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => [ - $config['hash_algorithm'], - $config['encode_as_base64'], - $config['iterations'], - $config['key_length'], - ], - ]; - } - - // bcrypt encoder - if ('bcrypt' === $config['algorithm']) { - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_BCRYPT; - - return $this->createEncoder($config); - } - - // Argon2i encoder - if ('argon2i' === $config['algorithm']) { - if (SodiumPasswordHasher::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $config['algorithm'] = 'sodium'; - } elseif (\defined('PASSWORD_ARGON2I')) { - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_ARGON2I; - } else { - throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available. Use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id", "auto' : 'auto')); - } - - return $this->createEncoder($config); - } - - if ('argon2id' === $config['algorithm']) { - if (($hasSodium = SodiumPasswordHasher::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $config['algorithm'] = 'sodium'; - } elseif (\defined('PASSWORD_ARGON2ID')) { - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_ARGON2ID; - } else { - throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. Either use "%s", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto')); - } - - return $this->createEncoder($config); - } - - if ('native' === $config['algorithm']) { - return [ - 'class' => NativePasswordEncoder::class, - 'arguments' => [ - $config['time_cost'], - (($config['memory_cost'] ?? 0) << 10) ?: null, - $config['cost'], - ] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []), - ]; - } - - if ('sodium' === $config['algorithm']) { - if (!SodiumPasswordHasher::isSupported()) { - throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use "auto" instead.'); - } - - return [ - 'class' => SodiumPasswordEncoder::class, - 'arguments' => [ - $config['time_cost'], - (($config['memory_cost'] ?? 0) << 10) ?: null, - ], - ]; - } - - // run-time configured encoder - return $config; - } - private function createHashers(array $hashers, ContainerBuilder $container) { $hasherMap = []; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/console.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/console.php index 5bfe8a2c3a2cf..5ab29caee1487 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/console.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/console.php @@ -11,20 +11,9 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand; use Symfony\Component\PasswordHasher\Command\UserPasswordHashCommand; return static function (ContainerConfigurator $container) { - $container->services() - ->set('security.command.user_password_encoder', UserPasswordEncoderCommand::class) - ->args([ - service('security.encoder_factory'), - abstract_arg('encoders user classes'), - ]) - ->tag('console.command', ['command' => 'security:encode-password']) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use "security.command.user_password_hash" instead.') - ; - $container->services() ->set('security.command.user_password_hash', UserPasswordHashCommand::class) ->args([ diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd index 586948d2f73be..2a33572e29312 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd @@ -9,8 +9,6 @@ - - @@ -28,12 +26,6 @@ - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php index 276b4d14a35c1..82ccc7a8b5b2d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.php @@ -18,8 +18,6 @@ use Symfony\Bundle\SecurityBundle\Security\FirewallMap; use Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext; use Symfony\Component\Ldap\Security\LdapUserProvider; -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -33,10 +31,6 @@ use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter; use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter; use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; -use Symfony\Component\Security\Core\Encoder\EncoderFactory; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; -use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder; -use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Security; @@ -105,25 +99,6 @@ ->set('security.authentication.session_strategy_noop', SessionAuthenticationStrategy::class) ->args(['none']) - ->set('security.encoder_factory.generic', EncoderFactory::class) - ->args([ - [], - ]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use "security.password_hasher_factory" instead.') - ->alias('security.encoder_factory', 'security.encoder_factory.generic') - ->deprecate('symfony/security-bundle', '5.3', 'The "%alias_id%" service is deprecated, use "security.password_hasher_factory" instead.') - ->alias(EncoderFactoryInterface::class, 'security.encoder_factory') - ->deprecate('symfony/security-bundle', '5.3', 'The "%alias_id%" service is deprecated, use "'.PasswordHasherFactoryInterface::class.'" instead.') - - ->set('security.user_password_encoder.generic', UserPasswordEncoder::class) - ->args([service('security.encoder_factory')]) - ->deprecate('symfony/security-bundle', '5.3', 'The "%service_id%" service is deprecated, use "security.user_password_hasher" instead.') - ->alias('security.password_encoder', 'security.user_password_encoder.generic') - ->public() - ->deprecate('symfony/security-bundle', '5.3', 'The "%alias_id%" service is deprecated, use "security.password_hasher"" instead.') - ->alias(UserPasswordEncoderInterface::class, 'security.password_encoder') - ->deprecate('symfony/security-bundle', '5.3', 'The "%alias_id%" service is deprecated, use "'.UserPasswordHasherInterface::class.'" instead.') - ->set('security.user_checker', InMemoryUserChecker::class) ->set('security.expression_language', ExpressionLanguage::class) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index b48704cec9bf3..b05a2160d948f 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -23,8 +23,6 @@ use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher; use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; use Symfony\Component\Security\Http\Authentication\AuthenticatorManager; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge; @@ -441,294 +439,6 @@ public function testMerge() ], $container->getParameter('security.role_hierarchy.roles')); } - /** - * @group legacy - */ - public function testEncoders() - { - $container = $this->getContainer('legacy_encoders'); - - $this->assertEquals([[ - 'JMS\FooBundle\Entity\User1' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => [false], - ], - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), - 'JMS\FooBundle\Entity\User5' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => ['sha1', false, 5, 30], - ], - 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', - 'arguments' => [8, 102400, 15], - ], - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'auto', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); - } - - /** - * @group legacy - */ - public function testEncodersWithLibsodium() - { - if (!SodiumPasswordEncoder::isSupported()) { - $this->markTestSkipped('Libsodium is not available.'); - } - - $container = $this->getContainer('sodium_encoder'); - - $this->assertEquals([[ - 'JMS\FooBundle\Entity\User1' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => [false], - ], - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), - 'JMS\FooBundle\Entity\User5' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => ['sha1', false, 5, 30], - ], - 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', - 'arguments' => [8, 102400, 15], - ], - 'JMS\FooBundle\Entity\User7' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder', - 'arguments' => [8, 128 * 1024 * 1024], - ], - ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); - } - - /** - * @group legacy - */ - public function testEncodersWithArgon2i() - { - if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - - $container = $this->getContainer('argon2i_encoder'); - - $this->assertEquals([[ - 'JMS\FooBundle\Entity\User1' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => [false], - ], - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), - 'JMS\FooBundle\Entity\User5' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => ['sha1', false, 5, 30], - ], - 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', - 'arguments' => [8, 102400, 15], - ], - 'JMS\FooBundle\Entity\User7' => [ - 'class' => $sodium ? SodiumPasswordEncoder::class : NativePasswordEncoder::class, - 'arguments' => $sodium ? [256, 1] : [1, 262144, null, \PASSWORD_ARGON2I], - ], - ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); - } - - /** - * @group legacy - */ - public function testMigratingEncoder() - { - if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - - $container = $this->getContainer('migrating_encoder'); - - $this->assertEquals([[ - 'JMS\FooBundle\Entity\User1' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => [false], - ], - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), - 'JMS\FooBundle\Entity\User5' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => ['sha1', false, 5, 30], - ], - 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', - 'arguments' => [8, 102400, 15], - ], - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'argon2i', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => 256, - 'time_cost' => 1, - 'migrate_from' => ['bcrypt'], - ], - ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); - } - - /** - * @group legacy - */ - public function testEncodersWithBCrypt() - { - $container = $this->getContainer('bcrypt_encoder'); - - $this->assertEquals([[ - 'JMS\FooBundle\Entity\User1' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', - 'arguments' => [false], - ], - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'migrate_from' => [], - ], - 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), - 'JMS\FooBundle\Entity\User5' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', - 'arguments' => ['sha1', false, 5, 30], - ], - 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', - 'arguments' => [8, 102400, 15], - ], - 'JMS\FooBundle\Entity\User7' => [ - 'class' => NativePasswordEncoder::class, - 'arguments' => [null, null, 15, \PASSWORD_BCRYPT], - ], - ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); - } - public function testHashers() { $container = $this->getContainer('container1'); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php deleted file mode 100644 index ba1e1328b069d..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php +++ /dev/null @@ -1,13 +0,0 @@ -load('legacy_encoders.php'); - -$container->loadFromExtension('security', [ - 'encoders' => [ - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'argon2i', - 'memory_cost' => 256, - 'time_cost' => 1, - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php deleted file mode 100644 index 0a0a69b6dec0d..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php +++ /dev/null @@ -1,12 +0,0 @@ -load('legacy_encoders.php'); - -$container->loadFromExtension('security', [ - 'encoders' => [ - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'bcrypt', - 'cost' => 15, - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_encoders.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_encoders.php deleted file mode 100644 index d6206527e6180..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/legacy_encoders.php +++ /dev/null @@ -1,108 +0,0 @@ -loadFromExtension('security', [ - 'encoders' => [ - 'JMS\FooBundle\Entity\User1' => 'plaintext', - 'JMS\FooBundle\Entity\User2' => [ - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - ], - 'JMS\FooBundle\Entity\User3' => [ - 'algorithm' => 'md5', - ], - 'JMS\FooBundle\Entity\User4' => [ - 'id' => 'security.encoder.foo', - ], - 'JMS\FooBundle\Entity\User5' => [ - 'algorithm' => 'pbkdf2', - 'hash_algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 5, - 'key_length' => 30, - ], - 'JMS\FooBundle\Entity\User6' => [ - 'algorithm' => 'native', - 'time_cost' => 8, - 'memory_cost' => 100, - 'cost' => 15, - ], - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'auto', - ], - ], - 'providers' => [ - 'default' => [ - 'memory' => [ - 'users' => [ - 'foo' => ['password' => 'foo', 'roles' => 'ROLE_USER'], - ], - ], - ], - 'digest' => [ - 'memory' => [ - 'users' => [ - 'foo' => ['password' => 'foo', 'roles' => 'ROLE_USER, ROLE_ADMIN'], - ], - ], - ], - 'basic' => [ - 'memory' => [ - 'users' => [ - 'foo' => ['password' => '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', 'roles' => 'ROLE_SUPER_ADMIN'], - 'bar' => ['password' => '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', 'roles' => ['ROLE_USER', 'ROLE_ADMIN']], - ], - ], - ], - 'service' => [ - 'id' => 'user.manager', - ], - 'chain' => [ - 'chain' => [ - 'providers' => ['service', 'basic'], - ], - ], - ], - - 'firewalls' => [ - 'simple' => ['provider' => 'default', 'pattern' => '/login', 'security' => false], - 'secure' => ['stateless' => true, - 'provider' => 'default', - 'http_basic' => true, - 'form_login' => true, - 'anonymous' => true, - 'switch_user' => true, - 'x509' => true, - 'remote_user' => true, - 'logout' => true, - 'remember_me' => ['secret' => 'TheSecret'], - 'user_checker' => null, - ], - 'host' => [ - 'provider' => 'default', - 'pattern' => '/test', - 'host' => 'foo\\.example\\.org', - 'methods' => ['GET', 'POST'], - 'anonymous' => true, - 'http_basic' => true, - ], - 'with_user_checker' => [ - 'provider' => 'default', - 'user_checker' => 'app.user_checker', - 'anonymous' => true, - 'http_basic' => true, - ], - ], - - 'access_control' => [ - ['path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => ['get', 'POST'], 'port' => 8000], - ['path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'], - ['path' => '/blog/524', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'allow_if' => "token.getUserIdentifier() matches '/^admin/'"], - ], - - 'role_hierarchy' => [ - 'ROLE_ADMIN' => 'ROLE_USER', - 'ROLE_SUPER_ADMIN' => ['ROLE_USER', 'ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'], - 'ROLE_REMOTE' => 'ROLE_USER,ROLE_ADMIN', - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php deleted file mode 100644 index 04a800a218c59..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php +++ /dev/null @@ -1,14 +0,0 @@ -load('legacy_encoders.php'); - -$container->loadFromExtension('security', [ - 'encoders' => [ - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'argon2i', - 'memory_cost' => 256, - 'time_cost' => 1, - 'migrate_from' => 'bcrypt', - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php deleted file mode 100644 index 3239ed027422b..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php +++ /dev/null @@ -1,13 +0,0 @@ -load('legacy_encoders.php'); - -$container->loadFromExtension('security', [ - 'encoders' => [ - 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'sodium', - 'time_cost' => 8, - 'memory_cost' => 128 * 1024, - ], - ], -]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2i_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2i_encoder.xml deleted file mode 100644 index d18ecd939cbb3..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2i_encoder.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml deleted file mode 100644 index 2ac6f38dd476c..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_encoders.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_encoders.xml deleted file mode 100644 index a362a59a15b80..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/legacy_encoders.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - app.user_checker - - - ROLE_USER - ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH - ROLE_USER,ROLE_ADMIN - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/migrating_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/migrating_encoder.xml deleted file mode 100644 index a4bd11688e288..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/migrating_encoder.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - bcrypt - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml deleted file mode 100644 index 80ccadf4511cb..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2i_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2i_encoder.yml deleted file mode 100644 index f4571e678db08..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2i_encoder.yml +++ /dev/null @@ -1,9 +0,0 @@ -imports: - - { resource: legacy_encoders.yml } - -security: - encoders: - JMS\FooBundle\Entity\User7: - algorithm: argon2i - memory_cost: 256 - time_cost: 1 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml deleted file mode 100644 index a5bd7d9b3bbce..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml +++ /dev/null @@ -1,8 +0,0 @@ -imports: - - { resource: legacy_encoders.yml } - -security: - encoders: - JMS\FooBundle\Entity\User7: - algorithm: bcrypt - cost: 15 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_encoders.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_encoders.yml deleted file mode 100644 index d80a99afcfca3..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/legacy_encoders.yml +++ /dev/null @@ -1,87 +0,0 @@ -security: - encoders: - JMS\FooBundle\Entity\User1: plaintext - JMS\FooBundle\Entity\User2: - algorithm: sha1 - encode_as_base64: false - iterations: 5 - JMS\FooBundle\Entity\User3: - algorithm: md5 - JMS\FooBundle\Entity\User4: - id: security.encoder.foo - JMS\FooBundle\Entity\User5: - algorithm: pbkdf2 - hash_algorithm: sha1 - encode_as_base64: false - iterations: 5 - key_length: 30 - JMS\FooBundle\Entity\User6: - algorithm: native - time_cost: 8 - memory_cost: 100 - cost: 15 - JMS\FooBundle\Entity\User7: - algorithm: auto - - providers: - default: - memory: - users: - foo: { password: foo, roles: ROLE_USER } - digest: - memory: - users: - foo: { password: foo, roles: 'ROLE_USER, ROLE_ADMIN' } - basic: - memory: - users: - foo: { password: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, roles: ROLE_SUPER_ADMIN } - bar: { password: 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33, roles: [ROLE_USER, ROLE_ADMIN] } - service: - id: user.manager - chain: - chain: - providers: [service, basic] - - - firewalls: - simple: { pattern: /login, security: false } - secure: - provider: default - stateless: true - http_basic: true - form_login: true - anonymous: true - switch_user: - x509: true - remote_user: true - logout: true - remember_me: - secret: TheSecret - user_checker: ~ - - host: - provider: default - pattern: /test - host: foo\.example\.org - methods: [GET,POST] - anonymous: true - http_basic: true - - with_user_checker: - provider: default - anonymous: ~ - http_basic: ~ - user_checker: app.user_checker - - role_hierarchy: - ROLE_ADMIN: ROLE_USER - ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] - ROLE_REMOTE: ROLE_USER,ROLE_ADMIN - - access_control: - - { path: /blog/524, role: ROLE_USER, requires_channel: https, methods: [get, POST], port: 8000} - - - path: /blog/.* - role: IS_AUTHENTICATED_ANONYMOUSLY - - { path: /blog/524, role: IS_AUTHENTICATED_ANONYMOUSLY, allow_if: "token.getUserIdentifier() matches '/^admin/'" } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/migrating_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/migrating_encoder.yml deleted file mode 100644 index 87943cac128ff..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/migrating_encoder.yml +++ /dev/null @@ -1,10 +0,0 @@ -imports: - - { resource: legacy_encoders.yml } - -security: - encoders: - JMS\FooBundle\Entity\User7: - algorithm: argon2i - memory_cost: 256 - time_cost: 1 - migrate_from: bcrypt diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml deleted file mode 100644 index 70b4455ce2ebe..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml +++ /dev/null @@ -1,9 +0,0 @@ -imports: - - { resource: legacy_encoders.yml } - -security: - encoders: - JMS\FooBundle\Entity\User7: - algorithm: sodium - time_cost: 8 - memory_cost: 131072 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php deleted file mode 100644 index 15e218856b571..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ /dev/null @@ -1,386 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\SecurityBundle\Tests\Functional; - -use Symfony\Bundle\FrameworkBundle\Console\Application; -use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand; -use Symfony\Component\Console\Application as ConsoleApplication; -use Symfony\Component\Console\Tester\CommandTester; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder; -use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; -use Symfony\Component\Security\Core\User\InMemoryUser; - -/** - * Tests UserPasswordEncoderCommand. - * - * @author Sarah Khalil - * @group legacy - */ -class UserPasswordEncoderCommandTest extends AbstractWebTestCase -{ - /** @var CommandTester */ - private $passwordEncoderCommandTester; - private $colSize; - - public function testEncodePasswordEmptySalt() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => InMemoryUser::class, - '--empty-salt' => true, - ], ['decorated' => false]); - $expected = str_replace("\n", \PHP_EOL, file_get_contents(__DIR__.'/app/PasswordEncode/emptysalt.txt')); - - $this->assertStringContainsString($expected, $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodeNoPasswordNoInteraction() - { - $statusCode = $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - ], ['interactive' => false]); - - $this->assertStringContainsString('[ERROR] The password must not be empty.', $this->passwordEncoderCommandTester->getDisplay()); - $this->assertEquals(1, $statusCode); - } - - public function testEncodePasswordBcrypt() - { - $this->setupBcrypt(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Bcrypt\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - $encoder = new NativePasswordEncoder(null, null, 17, \PASSWORD_BCRYPT); - preg_match('# Encoded password\s{1,}([\w+\/$.]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); - } - - public function testEncodePasswordArgon2i() - { - if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('Argon2i algorithm not available.'); - } - $this->setupArgon2i(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Argon2i\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - $encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, \PASSWORD_ARGON2I); - preg_match('# Encoded password\s+(\$argon2i?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); - } - - public function testEncodePasswordArgon2id() - { - if (!($sodium = (SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'))) && !\defined('PASSWORD_ARGON2ID')) { - $this->markTestSkipped('Argon2id algorithm not available.'); - } - $this->setupArgon2id(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Argon2id\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - $encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, \PASSWORD_ARGON2ID); - preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); - } - - public function testEncodePasswordNative() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Native\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - $encoder = new NativePasswordEncoder(); - preg_match('# Encoded password\s{1,}([\w+\/$.,=]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); - } - - public function testEncodePasswordSodium() - { - if (!SodiumPasswordEncoder::isSupported()) { - $this->markTestSkipped('Libsodium is not available.'); - } - $this->setupSodium(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Sodium\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - preg_match('# Encoded password\s+(\$?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - $this->assertTrue((new SodiumPasswordEncoder())->isPasswordValid($hash, 'password', null)); - } - - public function testEncodePasswordPbkdf2() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Custom\Class\Pbkdf2\User', - ], ['interactive' => false]); - - $output = $this->passwordEncoderCommandTester->getDisplay(); - $this->assertStringContainsString('Password encoding succeeded', $output); - - $encoder = new Pbkdf2PasswordEncoder('sha512', true, 1000); - preg_match('# Encoded password\s{1,}([\w+\/]+={0,2})\s+#', $output, $matches); - $hash = $matches[1]; - preg_match('# Generated salt\s{1,}([\w+\/]+={0,2})\s+#', $output, $matches); - $salt = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', $salt)); - } - - public function testEncodePasswordOutput() - { - $this->passwordEncoderCommandTester->execute( - [ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - ], ['interactive' => false] - ); - - $this->assertStringContainsString('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay()); - $this->assertStringContainsString(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay()); - $this->assertStringContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordEmptySaltOutput() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - 'user-class' => InMemoryUser::class, - '--empty-salt' => true, - ]); - - $this->assertStringContainsString('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay()); - $this->assertStringContainsString(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay()); - $this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordNativeOutput() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Native\User', - ], ['interactive' => false]); - - $this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordArgon2iOutput() - { - if (!(SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('Argon2i algorithm not available.'); - } - - $this->setupArgon2i(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Argon2i\User', - ], ['interactive' => false]); - - $this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordArgon2idOutput() - { - if (!(SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2ID')) { - $this->markTestSkipped('Argon2id algorithm not available.'); - } - - $this->setupArgon2id(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Argon2id\User', - ], ['interactive' => false]); - - $this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordSodiumOutput() - { - if (!SodiumPasswordEncoder::isSupported()) { - $this->markTestSkipped('Libsodium is not available.'); - } - - $this->setupSodium(); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Sodium\User', - ], ['interactive' => false]); - - $this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testEncodePasswordNoConfigForGivenUserClass() - { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('No encoder has been configured for account "Foo\Bar\User".'); - - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - 'user-class' => 'Foo\Bar\User', - ], ['interactive' => false]); - } - - public function testEncodePasswordAsksNonProvidedUserClass() - { - $this->passwordEncoderCommandTester->setInputs(['Custom\Class\Pbkdf2\User', "\n"]); - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - ], ['decorated' => false]); - - $this->assertStringContainsString(<<passwordEncoderCommandTester->getDisplay(true)); - } - - public function testNonInteractiveEncodePasswordUsesFirstUserClass() - { - $this->passwordEncoderCommandTester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - ], ['interactive' => false]); - - $this->assertStringContainsString('Encoder used Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', $this->passwordEncoderCommandTester->getDisplay()); - } - - public function testThrowsExceptionOnNoConfiguredEncoders() - { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('There are no configured encoders for the "security" extension.'); - $application = new ConsoleApplication(); - $application->add(new UserPasswordEncoderCommand($this->createMock(EncoderFactoryInterface::class), [])); - - $passwordEncoderCommand = $application->find('security:encode-password'); - - $tester = new CommandTester($passwordEncoderCommand); - $tester->execute([ - 'command' => 'security:encode-password', - 'password' => 'password', - ], ['interactive' => false]); - } - - protected function setUp(): void - { - $this->colSize = getenv('COLUMNS'); - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); - - $kernel = $this->createKernel(['test_case' => 'PasswordEncode']); - $kernel->boot(); - - $application = new Application($kernel); - - $passwordEncoderCommand = $application->get('security:encode-password'); - - $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); - } - - protected function tearDown(): void - { - $this->passwordEncoderCommandTester = null; - putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); - } - - private function setupArgon2i() - { - $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2i.yml']); - $kernel->boot(); - - $application = new Application($kernel); - - $passwordEncoderCommand = $application->get('security:encode-password'); - - $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); - } - - private function setupArgon2id() - { - $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']); - $kernel->boot(); - - $application = new Application($kernel); - - $passwordEncoderCommand = $application->get('security:encode-password'); - - $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); - } - - private function setupBcrypt() - { - $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'bcrypt.yml']); - $kernel->boot(); - - $application = new Application($kernel); - - $passwordEncoderCommand = $application->get('security:encode-password'); - - $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); - } - - private function setupSodium() - { - $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'sodium.yml']); - $kernel->boot(); - - $application = new Application($kernel); - - $passwordEncoderCommand = $application->get('security:encode-password'); - - $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); - } -} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2i.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2i.yml deleted file mode 100644 index 2ca4f3461a6e9..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2i.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: config.yml } - -security: - encoders: - Custom\Class\Argon2i\User: - algorithm: argon2i diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml deleted file mode 100644 index 481262acb7e6c..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: config.yml } - -security: - encoders: - Custom\Class\Argon2id\User: - algorithm: argon2id diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml deleted file mode 100644 index 1928c0400b722..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: config.yml } - -security: - encoders: - Custom\Class\Bcrypt\User: - algorithm: bcrypt diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bundles.php deleted file mode 100644 index edf6dae14c064..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bundles.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -return [ - new Symfony\Bundle\SecurityBundle\SecurityBundle(), - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\TestBundle(), -]; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml deleted file mode 100644 index 891b08b9c0a56..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -security: - encoders: - Symfony\Component\Security\Core\User\InMemoryUser: plaintext - Custom\Class\Native\User: - algorithm: native - cost: 10 - Custom\Class\Pbkdf2\User: - algorithm: pbkdf2 - hash_algorithm: sha512 - encode_as_base64: true - iterations: 1000 - Custom\Class\Test\User: test - - providers: - in_memory: - memory: - users: - user: { password: userpass, roles: [ 'ROLE_USER' ] } - admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } - - firewalls: - test: - pattern: ^/ - security: false diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/emptysalt.txt b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/emptysalt.txt deleted file mode 100644 index 9c8d3deb1b462..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/emptysalt.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Symfony Password Encoder Utility -================================ - - ------------------ ------------------------------------------------------------------ - Key Value - ------------------ ------------------------------------------------------------------ - Encoder used Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder - Encoded password password - ------------------ ------------------------------------------------------------------ - - [OK] Password encoding succeeded - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml deleted file mode 100644 index 1ccc2a10d5f6e..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: config.yml } - -security: - encoders: - Custom\Class\Sodium\User: - algorithm: sodium diff --git a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php index a205617c63756..2e9684a40a67d 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php @@ -13,9 +13,6 @@ use Symfony\Component\PasswordHasher\Exception\LogicException; use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; -use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; -use Symfony\Component\Security\Core\Encoder\PasswordHasherAdapter; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; /** @@ -43,7 +40,7 @@ public function getPasswordHasher(string|PasswordAuthenticatedUserInterface|Pass { $hasherKey = null; - if (($user instanceof PasswordHasherAwareInterface && null !== $hasherName = $user->getPasswordHasherName()) || ($user instanceof EncoderAwareInterface && null !== $hasherName = $user->getEncoderName())) { + if (($user instanceof PasswordHasherAwareInterface && null !== $hasherName = $user->getPasswordHasherName())) { if (!\array_key_exists($hasherName, $this->passwordHashers)) { throw new \RuntimeException(sprintf('The password hasher "%s" was not configured.', $hasherName)); } @@ -63,10 +60,7 @@ public function getPasswordHasher(string|PasswordAuthenticatedUserInterface|Pass } if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) { - $this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface - ? new PasswordHasherAdapter($this->passwordHashers[$hasherKey]) - : $this->createHasher($this->passwordHashers[$hasherKey]) - ; + $this->passwordHashers[$hasherKey] = $this->createHasher($this->passwordHashers[$hasherKey]); } return $this->passwordHashers[$hasherKey]; @@ -91,9 +85,6 @@ private function createHasher(array $config, bool $isExtra = false): PasswordHas } $hasher = new $config['class'](...$config['arguments']); - if (!$hasher instanceof PasswordHasherInterface && $hasher instanceof PasswordEncoderInterface) { - $hasher = new PasswordHasherAdapter($hasher); - } if ($isExtra || !\in_array($config['class'], [NativePasswordHasher::class, SodiumPasswordHasher::class], true)) { return $hasher; diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php index 1f8fcb3e79531..f1851cc588058 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php @@ -19,7 +19,6 @@ use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher; use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; @@ -184,24 +183,6 @@ public function testDefaultMigratingHashers() (new PasswordHasherFactory([SomeUser::class => ['class' => SodiumPasswordHasher::class, 'arguments' => []]]))->getPasswordHasher(SomeUser::class) ); } - - /** - * @group legacy - */ - public function testLegacyEncoderObject() - { - $factory = new PasswordHasherFactory([SomeUser::class => new PlaintextPasswordEncoder()]); - self::assertSame('foo{bar}', $factory->getPasswordHasher(SomeUser::class)->hash('foo', 'bar')); - } - - /** - * @group legacy - */ - public function testLegacyEncoderClass() - { - $factory = new PasswordHasherFactory([SomeUser::class => ['class' => PlaintextPasswordEncoder::class, 'arguments' => []]]); - self::assertSame('foo{bar}', $factory->getPasswordHasher(SomeUser::class)->hash('foo', 'bar')); - } } class SomeUser implements PasswordAuthenticatedUserInterface diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php index 84647a3b91b91..d7e6dc5b5c389 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\PasswordHasher\Tests\Hasher; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\PasswordHasher\Hasher\NativePasswordHasher; use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; @@ -24,8 +23,6 @@ class UserPasswordHasherTest extends TestCase { - use ExpectDeprecationTrait; - public function testHashWithLegacyUser() { $user = new TestLegacyPasswordAuthenticatedUser('name', null, 'userSalt'); diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index d83c1a0ca77a6..03f096416cd28 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -13,7 +13,6 @@ use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; @@ -39,17 +38,10 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider private $hasherFactory; private $userProvider; - /** - * @param PasswordHasherFactoryInterface $hasherFactory - */ - public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, $hasherFactory, bool $hideUserNotFoundExceptions = true) + public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, PasswordHasherFactoryInterface $hasherFactory, bool $hideUserNotFoundExceptions = true) { parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions); - if ($hasherFactory instanceof EncoderFactoryInterface) { - trigger_deprecation('symfony/security-core', '5.3', 'Passing a "%s" instance to the "%s" constructor is deprecated, use "%s" instead.', EncoderFactoryInterface::class, __CLASS__, PasswordHasherFactoryInterface::class); - } - $this->hasherFactory = $hasherFactory; $this->userProvider = $userProvider; } @@ -82,21 +74,6 @@ protected function checkAuthentication(UserInterface $user, UsernamePasswordToke trigger_deprecation('symfony/security-core', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); } - // deprecated since Symfony 5.3 - if ($this->hasherFactory instanceof EncoderFactoryInterface) { - $encoder = $this->hasherFactory->getEncoder($user); - - if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $salt)) { - throw new BadCredentialsException('The presented password is invalid.'); - } - - if ($this->userProvider instanceof PasswordUpgraderInterface && method_exists($encoder, 'needsRehash') && $encoder->needsRehash($user->getPassword())) { - $this->userProvider->upgradePassword($user, $encoder->encodePassword($presentedPassword, $user->getSalt())); - } - - return; - } - $hasher = $this->hasherFactory->getPasswordHasher($user); if (!$hasher->verify($user->getPassword(), $presentedPassword, $salt)) { diff --git a/src/Symfony/Component/Security/Core/CHANGELOG.md b/src/Symfony/Component/Security/Core/CHANGELOG.md index c60960c6b34f3..6e836c3048b3d 100644 --- a/src/Symfony/Component/Security/Core/CHANGELOG.md +++ b/src/Symfony/Component/Security/Core/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * `TokenInterface` does not extend `Serializable` anymore + * Remove all classes in the `Core\Encoder\` sub-namespace, use the `PasswordHasher` component instead 5.3 --- diff --git a/src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php deleted file mode 100644 index 21c59b3ceafc5..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php +++ /dev/null @@ -1,102 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', BasePasswordEncoder::class, CheckPasswordLengthTrait::class); - -/** - * BasePasswordEncoder is the base class for all password encoders. - * - * @author Fabien Potencier - * - * @deprecated since Symfony 5.3, use CheckPasswordLengthTrait instead - */ -abstract class BasePasswordEncoder implements PasswordEncoderInterface -{ - public const MAX_PASSWORD_LENGTH = 4096; - - /** - * {@inheritdoc} - */ - public function needsRehash(string $encoded): bool - { - return false; - } - - /** - * Demerges a merge password and salt string. - * - * @return array An array where the first element is the password and the second the salt - */ - protected function demergePasswordAndSalt(string $mergedPasswordSalt) - { - if (empty($mergedPasswordSalt)) { - return ['', '']; - } - - $password = $mergedPasswordSalt; - $salt = ''; - $saltBegins = strrpos($mergedPasswordSalt, '{'); - - if (false !== $saltBegins && $saltBegins + 1 < \strlen($mergedPasswordSalt)) { - $salt = substr($mergedPasswordSalt, $saltBegins + 1, -1); - $password = substr($mergedPasswordSalt, 0, $saltBegins); - } - - return [$password, $salt]; - } - - /** - * Merges a password and a salt. - * - * @return string a merged password and salt - * - * @throws \InvalidArgumentException - */ - protected function mergePasswordAndSalt(string $password, ?string $salt) - { - if (empty($salt)) { - return $password; - } - - if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) { - throw new \InvalidArgumentException('Cannot use { or } in salt.'); - } - - return $password.'{'.$salt.'}'; - } - - /** - * Compares two passwords. - * - * This method implements a constant-time algorithm to compare passwords to - * avoid (remote) timing attacks. - * - * @return bool true if the two passwords are the same, false otherwise - */ - protected function comparePasswords(string $password1, string $password2) - { - return hash_equals($password1, $password2); - } - - /** - * Checks if the password is too long. - * - * @return bool true if the password is too long, false otherwise - */ - protected function isPasswordTooLong(string $password) - { - return \strlen($password) > static::MAX_PASSWORD_LENGTH; - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderAwareInterface.php b/src/Symfony/Component/Security/Core/Encoder/EncoderAwareInterface.php deleted file mode 100644 index 70231e2ce3de0..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderAwareInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface; - -/** - * @author Christophe Coevoet - * - * @deprecated since Symfony 5.3, use {@link PasswordHasherAwareInterface} instead. - */ -interface EncoderAwareInterface -{ - /** - * Gets the name of the encoder used to encode the password. - * - * If the method returns null, the standard way to retrieve the encoder - * will be used instead. - * - * @return string|null - */ - public function getEncoderName(); -} diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php deleted file mode 100644 index 526c461e5ec40..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ /dev/null @@ -1,227 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface; -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; -use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface; -use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Exception\LogicException; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', EncoderFactory::class, PasswordHasherFactory::class); - -/** - * A generic encoder factory implementation. - * - * @author Johannes M. Schmitt - * - * @deprecated since Symfony 5.3, use {@link PasswordHasherFactory} instead - */ -class EncoderFactory implements EncoderFactoryInterface -{ - private $encoders; - - public function __construct(array $encoders) - { - $this->encoders = $encoders; - } - - /** - * {@inheritdoc} - */ - public function getEncoder($user) - { - $encoderKey = null; - - if (($user instanceof PasswordHasherAwareInterface && null !== $encoderName = $user->getPasswordHasherName()) || ($user instanceof EncoderAwareInterface && null !== $encoderName = $user->getEncoderName())) { - if (!\array_key_exists($encoderName, $this->encoders)) { - throw new \RuntimeException(sprintf('The encoder "%s" was not configured.', $encoderName)); - } - - $encoderKey = $encoderName; - } else { - foreach ($this->encoders as $class => $encoder) { - if ((\is_object($user) && $user instanceof $class) || (!\is_object($user) && (is_subclass_of($user, $class) || $user == $class))) { - $encoderKey = $class; - break; - } - } - } - - if (null === $encoderKey) { - throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', \is_object($user) ? get_debug_type($user) : $user)); - } - - if (!$this->encoders[$encoderKey] instanceof PasswordEncoderInterface) { - if ($this->encoders[$encoderKey] instanceof LegacyPasswordHasherInterface) { - $this->encoders[$encoderKey] = new LegacyPasswordHasherEncoder($this->encoders[$encoderKey]); - } elseif ($this->encoders[$encoderKey] instanceof PasswordHasherInterface) { - $this->encoders[$encoderKey] = new PasswordHasherEncoder($this->encoders[$encoderKey]); - } else { - $this->encoders[$encoderKey] = $this->createEncoder($this->encoders[$encoderKey]); - } - } - - return $this->encoders[$encoderKey]; - } - - /** - * Creates the actual encoder instance. - * - * @throws \InvalidArgumentException - */ - private function createEncoder(array $config, bool $isExtra = false): PasswordEncoderInterface - { - if (isset($config['algorithm'])) { - $rawConfig = $config; - $config = $this->getEncoderConfigFromAlgorithm($config); - } - if (!isset($config['class'])) { - throw new \InvalidArgumentException('"class" must be set in '.json_encode($config)); - } - if (!isset($config['arguments'])) { - throw new \InvalidArgumentException('"arguments" must be set in '.json_encode($config)); - } - - $encoder = new $config['class'](...$config['arguments']); - - if ($isExtra || !\in_array($config['class'], [NativePasswordEncoder::class, SodiumPasswordEncoder::class], true)) { - return $encoder; - } - - if ($rawConfig ?? null) { - $extraEncoders = array_map(function (string $algo) use ($rawConfig): PasswordEncoderInterface { - $rawConfig['algorithm'] = $algo; - - return $this->createEncoder($rawConfig); - }, ['pbkdf2', $rawConfig['hash_algorithm'] ?? 'sha512']); - } else { - $extraEncoders = [new Pbkdf2PasswordEncoder(), new MessageDigestPasswordEncoder()]; - } - - return new MigratingPasswordEncoder($encoder, ...$extraEncoders); - } - - private function getEncoderConfigFromAlgorithm(array $config): array - { - if ('auto' === $config['algorithm']) { - $encoderChain = []; - // "plaintext" is not listed as any leaked hashes could then be used to authenticate directly - foreach ([SodiumPasswordEncoder::isSupported() ? 'sodium' : 'native', 'pbkdf2', $config['hash_algorithm']] as $algo) { - $config['algorithm'] = $algo; - $encoderChain[] = $this->createEncoder($config, true); - } - - return [ - 'class' => MigratingPasswordEncoder::class, - 'arguments' => $encoderChain, - ]; - } - - if ($fromEncoders = ($config['migrate_from'] ?? false)) { - unset($config['migrate_from']); - $encoderChain = [$this->createEncoder($config, true)]; - - foreach ($fromEncoders as $name) { - if ($encoder = $this->encoders[$name] ?? false) { - $encoder = $encoder instanceof PasswordEncoderInterface ? $encoder : $this->createEncoder($encoder, true); - } else { - $encoder = $this->createEncoder(['algorithm' => $name], true); - } - - $encoderChain[] = $encoder; - } - - return [ - 'class' => MigratingPasswordEncoder::class, - 'arguments' => $encoderChain, - ]; - } - - switch ($config['algorithm']) { - case 'plaintext': - return [ - 'class' => PlaintextPasswordEncoder::class, - 'arguments' => [$config['ignore_case']], - ]; - - case 'pbkdf2': - return [ - 'class' => Pbkdf2PasswordEncoder::class, - 'arguments' => [ - $config['hash_algorithm'] ?? 'sha512', - $config['encode_as_base64'] ?? true, - $config['iterations'] ?? 1000, - $config['key_length'] ?? 40, - ], - ]; - - case 'bcrypt': - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_BCRYPT; - - return $this->getEncoderConfigFromAlgorithm($config); - - case 'native': - return [ - 'class' => NativePasswordEncoder::class, - 'arguments' => [ - $config['time_cost'] ?? null, - (($config['memory_cost'] ?? 0) << 10) ?: null, - $config['cost'] ?? null, - ] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []), - ]; - - case 'sodium': - return [ - 'class' => SodiumPasswordEncoder::class, - 'arguments' => [ - $config['time_cost'] ?? null, - (($config['memory_cost'] ?? 0) << 10) ?: null, - ], - ]; - - case 'argon2i': - if (SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $config['algorithm'] = 'sodium'; - } elseif (\defined('PASSWORD_ARGON2I')) { - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_ARGON2I; - } else { - throw new LogicException(sprintf('Algorithm "argon2i" is not available. Either use %s"auto" or upgrade to PHP 7.2+ instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? '"argon2id", ' : '')); - } - - return $this->getEncoderConfigFromAlgorithm($config); - - case 'argon2id': - if (($hasSodium = SodiumPasswordEncoder::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $config['algorithm'] = 'sodium'; - } elseif (\defined('PASSWORD_ARGON2ID')) { - $config['algorithm'] = 'native'; - $config['native_algorithm'] = \PASSWORD_ARGON2ID; - } else { - throw new LogicException(sprintf('Algorithm "argon2id" is not available. Either use %s"auto", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? '"argon2i", ' : '')); - } - - return $this->getEncoderConfigFromAlgorithm($config); - } - - return [ - 'class' => MessageDigestPasswordEncoder::class, - 'arguments' => [ - $config['algorithm'], - $config['encode_as_base64'] ?? true, - $config['iterations'] ?? 5000, - ], - ]; - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactoryInterface.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactoryInterface.php deleted file mode 100644 index 83dea6c734ebe..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactoryInterface.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; -use Symfony\Component\Security\Core\User\UserInterface; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', EncoderFactoryInterface::class, PasswordHasherFactoryInterface::class); - -/** - * EncoderFactoryInterface to support different encoders for different accounts. - * - * @author Johannes M. Schmitt - * - * @deprecated since Symfony 5.3, use {@link PasswordHasherFactoryInterface} instead - */ -interface EncoderFactoryInterface -{ - /** - * Returns the password encoder to use for the given account. - * - * @param UserInterface|string $user A UserInterface instance or a class name - * - * @return PasswordEncoderInterface - * - * @throws \RuntimeException when no password encoder could be found for the user - */ - public function getEncoder($user); -} diff --git a/src/Symfony/Component/Security/Core/Encoder/LegacyEncoderTrait.php b/src/Symfony/Component/Security/Core/Encoder/LegacyEncoderTrait.php deleted file mode 100644 index d1263213fe309..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/LegacyEncoderTrait.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException; -use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface; -use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * @internal - */ -trait LegacyEncoderTrait -{ - /** - * @var PasswordHasherInterface|LegacyPasswordHasherInterface - */ - private $hasher; - - /** - * {@inheritdoc} - */ - public function encodePassword(string $raw, ?string $salt): string - { - try { - return $this->hasher->hash($raw, $salt); - } catch (InvalidPasswordException $e) { - throw new BadCredentialsException('Bad credentials.'); - } - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool - { - return $this->hasher->verify($encoded, $raw, $salt); - } - - /** - * {@inheritdoc} - */ - public function needsRehash(string $encoded): bool - { - return $this->hasher->needsRehash($encoded); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/LegacyPasswordHasherEncoder.php b/src/Symfony/Component/Security/Core/Encoder/LegacyPasswordHasherEncoder.php deleted file mode 100644 index 7e57ff2383e05..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/LegacyPasswordHasherEncoder.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException; -use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * Forward compatibility for new new PasswordHasher component. - * - * @author Alexander M. Turek - * - * @internal To be removed in Symfony 6 - */ -final class LegacyPasswordHasherEncoder implements PasswordEncoderInterface -{ - private $passwordHasher; - - public function __construct(LegacyPasswordHasherInterface $passwordHasher) - { - $this->passwordHasher = $passwordHasher; - } - - public function encodePassword(string $raw, ?string $salt): string - { - try { - return $this->passwordHasher->hash($raw, $salt); - } catch (InvalidPasswordException $e) { - throw new BadCredentialsException($e->getMessage(), $e->getCode(), $e); - } - } - - public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool - { - return $this->passwordHasher->verify($encoded, $raw, $salt); - } - - public function needsRehash(string $encoded): bool - { - return $this->passwordHasher->needsRehash($encoded); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php deleted file mode 100644 index 2942c632787df..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php +++ /dev/null @@ -1,87 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', MessageDigestPasswordEncoder::class, MessageDigestPasswordHasher::class); - -/** - * MessageDigestPasswordEncoder uses a message digest algorithm. - * - * @author Fabien Potencier - * - * @deprecated since Symfony 5.3, use {@link MessageDigestPasswordHasher} instead - */ -class MessageDigestPasswordEncoder extends BasePasswordEncoder -{ - private $algorithm; - private $encodeHashAsBase64; - private $iterations = 1; - private $encodedLength = -1; - - /** - * @param string $algorithm The digest algorithm to use - * @param bool $encodeHashAsBase64 Whether to base64 encode the password hash - * @param int $iterations The number of iterations to use to stretch the password hash - */ - public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 5000) - { - $this->algorithm = $algorithm; - $this->encodeHashAsBase64 = $encodeHashAsBase64; - - try { - $this->encodedLength = \strlen($this->encodePassword('', 'salt')); - } catch (\LogicException $e) { - // ignore algorithm not supported - } - - $this->iterations = $iterations; - } - - /** - * {@inheritdoc} - */ - public function encodePassword(string $raw, ?string $salt) - { - if ($this->isPasswordTooLong($raw)) { - throw new BadCredentialsException('Invalid password.'); - } - - if (!\in_array($this->algorithm, hash_algos(), true)) { - throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm)); - } - - $salted = $this->mergePasswordAndSalt($raw, $salt); - $digest = hash($this->algorithm, $salted, true); - - // "stretch" hash - for ($i = 1; $i < $this->iterations; ++$i) { - $digest = hash($this->algorithm, $digest.$salted, true); - } - - return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest); - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid(string $encoded, string $raw, ?string $salt) - { - if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) { - return false; - } - - return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt)); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/MigratingPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/MigratingPasswordEncoder.php deleted file mode 100644 index 53d3a58ddc2c5..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/MigratingPasswordEncoder.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\MigratingPasswordHasher; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', MigratingPasswordEncoder::class, MigratingPasswordHasher::class); - -/** - * Hashes passwords using the best available encoder. - * Validates them using a chain of encoders. - * - * /!\ Don't put a PlaintextPasswordEncoder in the list as that'd mean a leaked hash - * could be used to authenticate successfully without knowing the cleartext password. - * - * @author Nicolas Grekas - * - * @deprecated since Symfony 5.3, use {@link MigratingPasswordHasher} instead - */ -final class MigratingPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface -{ - private $bestEncoder; - private $extraEncoders; - - public function __construct(PasswordEncoderInterface $bestEncoder, PasswordEncoderInterface ...$extraEncoders) - { - $this->bestEncoder = $bestEncoder; - $this->extraEncoders = $extraEncoders; - } - - /** - * {@inheritdoc} - */ - public function encodePassword(string $raw, ?string $salt): string - { - return $this->bestEncoder->encodePassword($raw, $salt); - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool - { - if ($this->bestEncoder->isPasswordValid($encoded, $raw, $salt)) { - return true; - } - - if (!$this->bestEncoder->needsRehash($encoded)) { - return false; - } - - foreach ($this->extraEncoders as $encoder) { - if ($encoder->isPasswordValid($encoded, $raw, $salt)) { - return true; - } - } - - return false; - } - - /** - * {@inheritdoc} - */ - public function needsRehash(string $encoded): bool - { - return $this->bestEncoder->needsRehash($encoded); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php deleted file mode 100644 index bc135bb17817d..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\NativePasswordHasher; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', NativePasswordEncoder::class, NativePasswordHasher::class); - -/** - * Hashes passwords using password_hash(). - * - * @author Elnur Abdurrakhimov - * @author Terje Bråten - * @author Nicolas Grekas - * - * @deprecated since Symfony 5.3, use {@link NativePasswordHasher} instead - */ -final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSaltingEncoderInterface -{ - use LegacyEncoderTrait; - - /** - * @param string|null $algo An algorithm supported by password_hash() or null to use the stronger available algorithm - */ - public function __construct(int $opsLimit = null, int $memLimit = null, int $cost = null, string $algo = null) - { - $this->hasher = new NativePasswordHasher($opsLimit, $memLimit, $cost, $algo); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/PasswordEncoderInterface.php b/src/Symfony/Component/Security/Core/Encoder/PasswordEncoderInterface.php deleted file mode 100644 index 45aa24edaa970..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/PasswordEncoderInterface.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', PasswordEncoderInterface::class, PasswordHasherInterface::class); - -/** - * PasswordEncoderInterface is the interface for all encoders. - * - * @author Fabien Potencier - * - * @deprecated since Symfony 5.3, use {@link PasswordHasherInterface} instead - */ -interface PasswordEncoderInterface -{ - /** - * Encodes the raw password. - * - * @return string The encoded password - * - * @throws BadCredentialsException If the raw password is invalid, e.g. excessively long - * @throws \InvalidArgumentException If the salt is invalid - */ - public function encodePassword(string $raw, ?string $salt); - - /** - * Checks a raw password against an encoded password. - * - * @param string $encoded An encoded password - * @param string $raw A raw password - * @param string|null $salt The salt - * - * @return bool true if the password is valid, false otherwise - * - * @throws \InvalidArgumentException If the salt is invalid - */ - public function isPasswordValid(string $encoded, string $raw, ?string $salt); - - /** - * Checks if an encoded password would benefit from rehashing. - */ - public function needsRehash(string $encoded): bool; -} diff --git a/src/Symfony/Component/Security/Core/Encoder/PasswordHasherAdapter.php b/src/Symfony/Component/Security/Core/Encoder/PasswordHasherAdapter.php deleted file mode 100644 index a8546a4c4fd97..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/PasswordHasherAdapter.php +++ /dev/null @@ -1,46 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface; - -/** - * Forward compatibility for new new PasswordHasher component. - * - * @author Alexander M. Turek - * - * @internal To be removed in Symfony 6 - */ -final class PasswordHasherAdapter implements LegacyPasswordHasherInterface -{ - private $passwordEncoder; - - public function __construct(PasswordEncoderInterface $passwordEncoder) - { - $this->passwordEncoder = $passwordEncoder; - } - - public function hash(string $plainPassword, string $salt = null): string - { - return $this->passwordEncoder->encodePassword($plainPassword, $salt); - } - - public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool - { - return $this->passwordEncoder->isPasswordValid($hashedPassword, $plainPassword, $salt); - } - - public function needsRehash(string $hashedPassword): bool - { - return $this->passwordEncoder->needsRehash($hashedPassword); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/PasswordHasherEncoder.php b/src/Symfony/Component/Security/Core/Encoder/PasswordHasherEncoder.php deleted file mode 100644 index d37875dcc2770..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/PasswordHasherEncoder.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException; -use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * Forward compatibility for new new PasswordHasher component. - * - * @author Alexander M. Turek - * - * @internal To be removed in Symfony 6 - */ -final class PasswordHasherEncoder implements PasswordEncoderInterface, SelfSaltingEncoderInterface -{ - private $passwordHasher; - - public function __construct(PasswordHasherInterface $passwordHasher) - { - $this->passwordHasher = $passwordHasher; - } - - public function encodePassword(string $raw, ?string $salt): string - { - if (null !== $salt) { - throw new \InvalidArgumentException('This password hasher does not support passing a salt.'); - } - - try { - return $this->passwordHasher->hash($raw); - } catch (InvalidPasswordException $e) { - throw new BadCredentialsException($e->getMessage(), $e->getCode(), $e); - } - } - - public function isPasswordValid(string $encoded, string $raw, ?string $salt): bool - { - if (null !== $salt) { - throw new \InvalidArgumentException('This password hasher does not support passing a salt.'); - } - - return $this->passwordHasher->verify($encoded, $raw); - } - - public function needsRehash(string $encoded): bool - { - return $this->passwordHasher->needsRehash($encoded); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/Pbkdf2PasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Pbkdf2PasswordEncoder.php deleted file mode 100644 index d92c12fc24a6a..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/Pbkdf2PasswordEncoder.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', Pbkdf2PasswordEncoder::class, Pbkdf2PasswordHasher::class); - -/** - * Pbkdf2PasswordEncoder uses the PBKDF2 (Password-Based Key Derivation Function 2). - * - * Providing a high level of Cryptographic security, - * PBKDF2 is recommended by the National Institute of Standards and Technology (NIST). - * - * But also warrants a warning, using PBKDF2 (with a high number of iterations) slows down the process. - * PBKDF2 should be used with caution and care. - * - * @author Sebastiaan Stok - * @author Andrew Johnson - * @author Fabien Potencier - * - * @deprecated since Symfony 5.3, use {@link Pbkdf2PasswordHasher} instead - */ -class Pbkdf2PasswordEncoder extends BasePasswordEncoder -{ - use LegacyEncoderTrait; - - /** - * @param string $algorithm The digest algorithm to use - * @param bool $encodeHashAsBase64 Whether to base64 encode the password hash - * @param int $iterations The number of iterations to use to stretch the password hash - * @param int $length Length of derived key to create - */ - public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 1000, int $length = 40) - { - $this->hasher = new Pbkdf2PasswordHasher($algorithm, $encodeHashAsBase64, $iterations, $length); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/PlaintextPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/PlaintextPasswordEncoder.php deleted file mode 100644 index 497e9f19ed5d4..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/PlaintextPasswordEncoder.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', PlaintextPasswordEncoder::class, PlaintextPasswordHasher::class); - -/** - * PlaintextPasswordEncoder does not do any encoding but is useful in testing environments. - * - * As this encoder is not cryptographically secure, usage of it in production environments is discouraged. - * - * @author Fabien Potencier - * - * @deprecated since Symfony 5.3, use {@link PlaintextPasswordHasher} instead - */ -class PlaintextPasswordEncoder extends BasePasswordEncoder -{ - use LegacyEncoderTrait; - - /** - * @param bool $ignorePasswordCase Compare password case-insensitive - */ - public function __construct(bool $ignorePasswordCase = false) - { - $this->hasher = new PlaintextPasswordHasher($ignorePasswordCase); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/SelfSaltingEncoderInterface.php b/src/Symfony/Component/Security/Core/Encoder/SelfSaltingEncoderInterface.php deleted file mode 100644 index b8740bc9dcb14..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/SelfSaltingEncoderInterface.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" interface is deprecated, use "%s" on hasher implementations that deal with salts instead.', SelfSaltingEncoderInterface::class, LegacyPasswordHasherInterface::class); - -/** - * SelfSaltingEncoderInterface is a marker interface for encoders that do not - * require a user-generated salt. - * - * @author Zan Baldwin - * - * @deprecated since Symfony 5.3, use {@link LegacyPasswordHasherInterface} instead - */ -interface SelfSaltingEncoderInterface -{ -} diff --git a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php deleted file mode 100644 index d2d71f482b68e..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', SodiumPasswordEncoder::class, SodiumPasswordHasher::class); - -/** - * Hashes passwords using libsodium. - * - * @author Robin Chalas - * @author Zan Baldwin - * @author Dominik Müller - * - * @deprecated since Symfony 5.3, use {@link SodiumPasswordHasher} instead - */ -final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSaltingEncoderInterface -{ - use LegacyEncoderTrait; - - public function __construct(int $opsLimit = null, int $memLimit = null) - { - $this->hasher = new SodiumPasswordHasher($opsLimit, $memLimit); - } - - public static function isSupported(): bool - { - return SodiumPasswordHasher::isSupported(); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php deleted file mode 100644 index 7b29918c0cfb7..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; -use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; -use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; -use Symfony\Component\Security\Core\User\UserInterface; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', UserPasswordEncoder::class, UserPasswordHasher::class); - -/** - * A generic password encoder. - * - * @author Ariel Ferrandini - * - * @deprecated since Symfony 5.3, use {@link UserPasswordHasher} instead - */ -class UserPasswordEncoder implements UserPasswordEncoderInterface -{ - private $encoderFactory; - - public function __construct(EncoderFactoryInterface $encoderFactory) - { - $this->encoderFactory = $encoderFactory; - } - - /** - * {@inheritdoc} - */ - public function encodePassword(UserInterface $user, string $plainPassword) - { - $encoder = $this->encoderFactory->getEncoder($user); - - if (!$user instanceof PasswordAuthenticatedUserInterface) { - trigger_deprecation('symfony/password-hasher', '5.3', 'Not implementing the "%s" interface while using "%s" is deprecated, the "%s" class should implement it.', PasswordAuthenticatedUserInterface::class, __CLASS__, get_debug_type($user)); - } - - $salt = $user->getSalt(); - if ($salt && !$user instanceof LegacyPasswordAuthenticatedUserInterface) { - trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); - } - - return $encoder->encodePassword($plainPassword, $user->getSalt()); - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid(UserInterface $user, string $raw) - { - if (null === $user->getPassword()) { - return false; - } - - $encoder = $this->encoderFactory->getEncoder($user); - - return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt()); - } - - /** - * {@inheritdoc} - */ - public function needsRehash(UserInterface $user): bool - { - if (null === $user->getPassword()) { - return false; - } - - $encoder = $this->encoderFactory->getEncoder($user); - - return $encoder->needsRehash($user->getPassword()); - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoderInterface.php b/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoderInterface.php deleted file mode 100644 index 488777c13411c..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoderInterface.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Encoder; - -use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; -use Symfony\Component\Security\Core\User\UserInterface; - -trigger_deprecation('symfony/security-core', '5.3', 'The "%s" interface is deprecated, use "%s" instead.', UserPasswordEncoderInterface::class, UserPasswordHasherInterface::class); - -/** - * UserPasswordEncoderInterface is the interface for the password encoder service. - * - * @author Ariel Ferrandini - * - * @deprecated since Symfony 5.3, use {@link UserPasswordHasherInterface} instead - */ -interface UserPasswordEncoderInterface -{ - /** - * Encodes the plain password. - * - * @return string The encoded password - */ - public function encodePassword(UserInterface $user, string $plainPassword); - - /** - * @return bool true if the password is valid, false otherwise - */ - public function isPasswordValid(UserInterface $user, string $raw); - - /** - * Checks if an encoded password would benefit from rehashing. - */ - public function needsRehash(UserInterface $user): bool; -} diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index 93c15d97530e9..2270680aeb3d0 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -18,7 +18,6 @@ use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\UserNotFoundException; @@ -53,18 +52,6 @@ public function testRetrieveUserWhenProviderDoesNotReturnAnUserInterface() $method->invoke($provider, 'fabien', $this->getSupportedToken()); } - public function testRetrieveUserWhenUsernameIsNotFoundWithLegacyEncoderFactory() - { - $this->expectException(UserNotFoundException::class); - $userProvider = new InMemoryUserProvider(); - - $provider = new DaoAuthenticationProvider($userProvider, $this->createMock(UserCheckerInterface::class), 'key', $this->createMock(EncoderFactoryInterface::class)); - $method = new \ReflectionMethod($provider, 'retrieveUser'); - $method->setAccessible(true); - - $method->invoke($provider, 'fabien', $this->getSupportedToken()); - } - public function testRetrieveUserWhenUsernameIsNotFound() { $this->expectException(UserNotFoundException::class); diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php deleted file mode 100644 index 7b05c9be0a93c..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php +++ /dev/null @@ -1,272 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher; -use Symfony\Component\PasswordHasher\Hasher\NativePasswordHasher; -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface; -use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory; -use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher; -use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; -use Symfony\Component\Security\Core\Encoder\EncoderFactory; -use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; -use Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\SelfSaltingEncoderInterface; -use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; -use Symfony\Component\Security\Core\User\User; -use Symfony\Component\Security\Core\User\UserInterface; - -/** - * @group legacy - */ -class EncoderFactoryTest extends TestCase -{ - public function testGetEncoderWithMessageDigestEncoder() - { - $factory = new EncoderFactory(['Symfony\Component\Security\Core\User\UserInterface' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', - 'arguments' => ['sha512', true, 5], - ]]); - - $encoder = $factory->getEncoder($this->createMock(UserInterface::class)); - $expectedEncoder = new MessageDigestPasswordEncoder('sha512', true, 5); - - $this->assertEquals($expectedEncoder->encodePassword('foo', 'moo'), $encoder->encodePassword('foo', 'moo')); - } - - public function testGetEncoderWithService() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\User\UserInterface' => new MessageDigestPasswordEncoder('sha1'), - ]); - - $encoder = $factory->getEncoder($this->createMock(UserInterface::class)); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - - $encoder = $factory->getEncoder(new User('user', 'pass')); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetEncoderWithClassName() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\User\UserInterface' => new MessageDigestPasswordEncoder('sha1'), - ]); - - $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\SomeChildUser'); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetEncoderConfiguredForConcreteClassWithService() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\User\User' => new MessageDigestPasswordEncoder('sha1'), - ]); - - $encoder = $factory->getEncoder(new User('user', 'pass')); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetEncoderConfiguredForConcreteClassWithClassName() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\Tests\Encoder\SomeUser' => new MessageDigestPasswordEncoder('sha1'), - ]); - - $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\SomeChildUser'); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetNamedEncoderForEncoderAware() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha256'), - 'encoder_name' => new MessageDigestPasswordEncoder('sha1'), - ]); - - $encoder = $factory->getEncoder(new EncAwareUser('user', 'pass')); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetNullNamedEncoderForEncoderAware() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), - 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), - ]); - - $user = new EncAwareUser('user', 'pass'); - $user->encoderName = null; - $encoder = $factory->getEncoder($user); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testGetInvalidNamedEncoderForEncoderAware() - { - $this->expectException(\RuntimeException::class); - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), - 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), - ]); - - $user = new EncAwareUser('user', 'pass'); - $user->encoderName = 'invalid_encoder_name'; - $factory->getEncoder($user); - } - - public function testGetEncoderForEncoderAwareWithClassName() - { - $factory = new EncoderFactory([ - 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), - 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), - ]); - - $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser'); - $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); - $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); - } - - public function testMigrateFrom() - { - if (!SodiumPasswordEncoder::isSupported()) { - $this->markTestSkipped('Sodium is not available'); - } - - $factory = new EncoderFactory([ - 'digest_encoder' => $digest = new MessageDigestPasswordEncoder('sha256'), - SomeUser::class => ['algorithm' => 'sodium', 'migrate_from' => ['bcrypt', 'digest_encoder']], - ]); - - $encoder = $factory->getEncoder(SomeUser::class); - $this->assertInstanceOf(MigratingPasswordEncoder::class, $encoder); - - $this->assertTrue($encoder->isPasswordValid((new SodiumPasswordEncoder())->encodePassword('foo', null), 'foo', null)); - $this->assertTrue($encoder->isPasswordValid((new NativePasswordEncoder(null, null, null, \PASSWORD_BCRYPT))->encodePassword('foo', null), 'foo', null)); - $this->assertTrue($encoder->isPasswordValid($digest->encodePassword('foo', null), 'foo', null)); - $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $encoder->encodePassword('foo', null)); - } - - public function testDefaultMigratingEncoders() - { - $this->assertInstanceOf( - MigratingPasswordEncoder::class, - (new EncoderFactory([SomeUser::class => ['class' => NativePasswordEncoder::class, 'arguments' => []]]))->getEncoder(SomeUser::class) - ); - - $this->assertInstanceOf( - MigratingPasswordEncoder::class, - (new EncoderFactory([SomeUser::class => ['algorithm' => 'bcrypt', 'cost' => 11]]))->getEncoder(SomeUser::class) - ); - - if (!SodiumPasswordEncoder::isSupported()) { - return; - } - - $this->assertInstanceOf( - MigratingPasswordEncoder::class, - (new EncoderFactory([SomeUser::class => ['class' => SodiumPasswordEncoder::class, 'arguments' => []]]))->getEncoder(SomeUser::class) - ); - } - - public function testHasherAwareCompat() - { - $factory = new PasswordHasherFactory([ - 'encoder_name' => new MessageDigestPasswordHasher('sha1'), - ]); - - $encoder = $factory->getPasswordHasher(new HasherAwareUser('user', 'pass')); - $expectedEncoder = new MessageDigestPasswordHasher('sha1'); - $this->assertEquals($expectedEncoder->hash('foo', ''), $encoder->hash('foo', '')); - } - - public function testLegacyPasswordHasher() - { - $factory = new EncoderFactory([ - SomeUser::class => new PlaintextPasswordHasher(), - ]); - - $encoder = $factory->getEncoder(new SomeUser()); - self::assertNotInstanceOf(SelfSaltingEncoderInterface::class, $encoder); - self::assertSame('foo{bar}', $encoder->encodePassword('foo', 'bar')); - } - - public function testPasswordHasher() - { - $factory = new EncoderFactory([ - SomeUser::class => new NativePasswordHasher(), - ]); - - $encoder = $factory->getEncoder(new SomeUser()); - self::assertInstanceOf(SelfSaltingEncoderInterface::class, $encoder); - self::assertTrue($encoder->isPasswordValid($encoder->encodePassword('foo', null), 'foo', null)); - } -} - -class SomeUser implements UserInterface -{ - public function getRoles(): array - { - } - - public function getPassword(): ?string - { - } - - public function getSalt(): ?string - { - } - - public function getUsername(): string - { - } - - public function getUserIdentifier(): string - { - } - - public function eraseCredentials() - { - } -} - -class SomeChildUser extends SomeUser -{ -} - -class EncAwareUser extends SomeUser implements EncoderAwareInterface -{ - public $encoderName = 'encoder_name'; - - public function getEncoderName(): ?string - { - return $this->encoderName; - } -} - -class HasherAwareUser extends SomeUser implements PasswordHasherAwareInterface -{ - public $hasherName = 'encoder_name'; - - public function getPasswordHasherName(): ?string - { - return $this->hasherName; - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Fixtures/MyMessageDigestPasswordEncoder.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Fixtures/MyMessageDigestPasswordEncoder.php deleted file mode 100644 index 110541d51084c..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Fixtures/MyMessageDigestPasswordEncoder.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder\Fixtures; - -use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; - -final class MyMessageDigestPasswordEncoder extends MessageDigestPasswordEncoder -{ - public function __construct() - { - parent::__construct('sha512', true, 1); - } - - protected function mergePasswordAndSalt(string $password, ?string $salt): string - { - return json_encode(['password' => $password, 'salt' => $salt]); - } - - protected function demergePasswordAndSalt(string $mergedPasswordSalt): array - { - ['password' => $password, 'salt' => $salt] = json_decode($mergedPasswordSalt, true); - - return [$password, $salt]; - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php deleted file mode 100644 index a9753957860fa..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; -use Symfony\Component\Security\Core\Tests\Encoder\Fixtures\MyMessageDigestPasswordEncoder; - -/** - * @group legacy - */ -class MessageDigestPasswordEncoderTest extends TestCase -{ - public function testIsPasswordValid() - { - $encoder = new MessageDigestPasswordEncoder('sha256', false, 1); - - $this->assertTrue($encoder->isPasswordValid(hash('sha256', 'password'), 'password', '')); - } - - public function testEncodePassword() - { - $encoder = new MessageDigestPasswordEncoder('sha256', false, 1); - $this->assertSame(hash('sha256', 'password'), $encoder->encodePassword('password', '')); - - $encoder = new MessageDigestPasswordEncoder('sha256', true, 1); - $this->assertSame(base64_encode(hash('sha256', 'password', true)), $encoder->encodePassword('password', '')); - - $encoder = new MessageDigestPasswordEncoder('sha256', false, 2); - $this->assertSame(hash('sha256', hash('sha256', 'password', true).'password'), $encoder->encodePassword('password', '')); - } - - public function testEncodePasswordAlgorithmDoesNotExist() - { - $this->expectException(\LogicException::class); - $encoder = new MessageDigestPasswordEncoder('foobar'); - $encoder->encodePassword('password', ''); - } - - public function testEncodePasswordLength() - { - $this->expectException(BadCredentialsException::class); - $encoder = new MessageDigestPasswordEncoder(); - - $encoder->encodePassword(str_repeat('a', 5000), 'salt'); - } - - public function testCheckPasswordLength() - { - $encoder = new MessageDigestPasswordEncoder(); - - $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt')); - } - - public function testCustomEncoder() - { - $encoder = new MyMessageDigestPasswordEncoder(); - $encodedPassword = $encoder->encodePassword('p4ssw0rd', 's417'); - - $this->assertSame(base64_encode(hash('sha512', '{"password":"p4ssw0rd","salt":"s417"}', true)), $encodedPassword); - $this->assertTrue($encoder->isPasswordValid($encodedPassword, 'p4ssw0rd', 's417')); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php deleted file mode 100644 index fbaf89b0b1b1a..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; - -/** - * @group legacy - */ -class MigratingPasswordEncoderTest extends TestCase -{ - public function testValidation() - { - $bestEncoder = new NativePasswordEncoder(4, 12000, 4); - - $extraEncoder = $this->createMock(TestPasswordEncoderInterface::class); - $extraEncoder->expects($this->never())->method('encodePassword'); - $extraEncoder->expects($this->never())->method('isPasswordValid'); - $extraEncoder->expects($this->never())->method('needsRehash'); - - $encoder = new MigratingPasswordEncoder($bestEncoder, $extraEncoder); - - $this->assertTrue($encoder->needsRehash('foo')); - - $hash = $encoder->encodePassword('foo', 'salt'); - $this->assertFalse($encoder->needsRehash($hash)); - - $this->assertTrue($encoder->isPasswordValid($hash, 'foo', 'salt')); - $this->assertFalse($encoder->isPasswordValid($hash, 'bar', 'salt')); - } - - public function testFallback() - { - $bestEncoder = new NativePasswordEncoder(4, 12000, 4); - - $extraEncoder1 = $this->createMock(TestPasswordEncoderInterface::class); - $extraEncoder1->expects($this->any()) - ->method('isPasswordValid') - ->with('abc', 'foo', 'salt') - ->willReturn(true); - - $encoder = new MigratingPasswordEncoder($bestEncoder, $extraEncoder1); - - $this->assertTrue($encoder->isPasswordValid('abc', 'foo', 'salt')); - - $extraEncoder2 = $this->createMock(TestPasswordEncoderInterface::class); - $extraEncoder2->expects($this->any()) - ->method('isPasswordValid') - ->willReturn(false); - - $encoder = new MigratingPasswordEncoder($bestEncoder, $extraEncoder2); - - $this->assertFalse($encoder->isPasswordValid('abc', 'foo', 'salt')); - - $encoder = new MigratingPasswordEncoder($bestEncoder, $extraEncoder2, $extraEncoder1); - - $this->assertTrue($encoder->isPasswordValid('abc', 'foo', 'salt')); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php deleted file mode 100644 index 9d864dfce038e..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php +++ /dev/null @@ -1,106 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; - -/** - * @author Elnur Abdurrakhimov - * @group legacy - */ -class NativePasswordEncoderTest extends TestCase -{ - public function testCostBelowRange() - { - $this->expectException(\InvalidArgumentException::class); - new NativePasswordEncoder(null, null, 3); - } - - public function testCostAboveRange() - { - $this->expectException(\InvalidArgumentException::class); - new NativePasswordEncoder(null, null, 32); - } - - /** - * @dataProvider validRangeData - */ - public function testCostInRange($cost) - { - $this->assertInstanceOf(NativePasswordEncoder::class, new NativePasswordEncoder(null, null, $cost)); - } - - public function validRangeData() - { - $costs = range(4, 31); - array_walk($costs, function (&$cost) { $cost = [$cost]; }); - - return $costs; - } - - public function testValidation() - { - $encoder = new NativePasswordEncoder(); - $result = $encoder->encodePassword('password', null); - $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); - $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); - $this->assertFalse($encoder->isPasswordValid($result, '', null)); - } - - public function testNonArgonValidation() - { - $encoder = new NativePasswordEncoder(); - $this->assertTrue($encoder->isPasswordValid('$5$abcdefgh$ZLdkj8mkc2XVSrPVjskDAgZPGjtj1VGVaa1aUkrMTU/', 'password', null)); - $this->assertFalse($encoder->isPasswordValid('$5$abcdefgh$ZLdkj8mkc2XVSrPVjskDAgZPGjtj1VGVaa1aUkrMTU/', 'anotherPassword', null)); - $this->assertTrue($encoder->isPasswordValid('$6$abcdefgh$yVfUwsw5T.JApa8POvClA1pQ5peiq97DUNyXCZN5IrF.BMSkiaLQ5kvpuEm/VQ1Tvh/KV2TcaWh8qinoW5dhA1', 'password', null)); - $this->assertFalse($encoder->isPasswordValid('$6$abcdefgh$yVfUwsw5T.JApa8POvClA1pQ5peiq97DUNyXCZN5IrF.BMSkiaLQ5kvpuEm/VQ1Tvh/KV2TcaWh8qinoW5dhA1', 'anotherPassword', null)); - } - - public function testConfiguredAlgorithm() - { - $encoder = new NativePasswordEncoder(null, null, null, \PASSWORD_BCRYPT); - $result = $encoder->encodePassword('password', null); - $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); - $this->assertStringStartsWith('$2', $result); - } - - public function testConfiguredAlgorithmWithLegacyConstValue() - { - $encoder = new NativePasswordEncoder(null, null, null, '1'); - $result = $encoder->encodePassword('password', null); - $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); - $this->assertStringStartsWith('$2', $result); - } - - public function testCheckPasswordLength() - { - $encoder = new NativePasswordEncoder(null, null, 4); - $result = password_hash(str_repeat('a', 72), \PASSWORD_BCRYPT, ['cost' => 4]); - - $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 73), 'salt')); - $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 72), 'salt')); - } - - public function testNeedsRehash() - { - $encoder = new NativePasswordEncoder(4, 11000, 4); - - $this->assertTrue($encoder->needsRehash('dummyhash')); - - $hash = $encoder->encodePassword('foo', 'salt'); - $this->assertFalse($encoder->needsRehash($hash)); - - $encoder = new NativePasswordEncoder(5, 11000, 5); - $this->assertTrue($encoder->needsRehash($hash)); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Pbkdf2PasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Pbkdf2PasswordEncoderTest.php deleted file mode 100644 index 000e07d659113..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Pbkdf2PasswordEncoderTest.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * @group legacy - */ -class Pbkdf2PasswordEncoderTest extends TestCase -{ - public function testIsPasswordValid() - { - $encoder = new Pbkdf2PasswordEncoder('sha256', false, 1, 40); - - $this->assertTrue($encoder->isPasswordValid('c1232f10f62715fda06ae7c0a2037ca19b33cf103b727ba56d870c11f290a2ab106974c75607c8a3', 'password', '')); - } - - public function testEncodePassword() - { - $encoder = new Pbkdf2PasswordEncoder('sha256', false, 1, 40); - $this->assertSame('c1232f10f62715fda06ae7c0a2037ca19b33cf103b727ba56d870c11f290a2ab106974c75607c8a3', $encoder->encodePassword('password', '')); - - $encoder = new Pbkdf2PasswordEncoder('sha256', true, 1, 40); - $this->assertSame('wSMvEPYnFf2gaufAogN8oZszzxA7cnulbYcMEfKQoqsQaXTHVgfIow==', $encoder->encodePassword('password', '')); - - $encoder = new Pbkdf2PasswordEncoder('sha256', false, 2, 40); - $this->assertSame('8bc2f9167a81cdcfad1235cd9047f1136271c1f978fcfcb35e22dbeafa4634f6fd2214218ed63ebb', $encoder->encodePassword('password', '')); - } - - public function testEncodePasswordAlgorithmDoesNotExist() - { - $this->expectException(\LogicException::class); - $encoder = new Pbkdf2PasswordEncoder('foobar'); - $encoder->encodePassword('password', ''); - } - - public function testEncodePasswordLength() - { - $this->expectException(BadCredentialsException::class); - $encoder = new Pbkdf2PasswordEncoder('foobar'); - - $encoder->encodePassword(str_repeat('a', 5000), 'salt'); - } - - public function testCheckPasswordLength() - { - $encoder = new Pbkdf2PasswordEncoder('foobar'); - - $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt')); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/PlaintextPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/PlaintextPasswordEncoderTest.php deleted file mode 100644 index 398044035eb61..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/PlaintextPasswordEncoderTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * @group legacy - */ -class PlaintextPasswordEncoderTest extends TestCase -{ - public function testIsPasswordValid() - { - $encoder = new PlaintextPasswordEncoder(); - - $this->assertTrue($encoder->isPasswordValid('foo', 'foo', '')); - $this->assertFalse($encoder->isPasswordValid('bar', 'foo', '')); - $this->assertFalse($encoder->isPasswordValid('FOO', 'foo', '')); - - $encoder = new PlaintextPasswordEncoder(true); - - $this->assertTrue($encoder->isPasswordValid('foo', 'foo', '')); - $this->assertFalse($encoder->isPasswordValid('bar', 'foo', '')); - $this->assertTrue($encoder->isPasswordValid('FOO', 'foo', '')); - } - - public function testEncodePassword() - { - $encoder = new PlaintextPasswordEncoder(); - - $this->assertSame('foo', $encoder->encodePassword('foo', '')); - } - - public function testEncodePasswordLength() - { - $this->expectException(BadCredentialsException::class); - $encoder = new PlaintextPasswordEncoder(); - - $encoder->encodePassword(str_repeat('a', 5000), 'salt'); - } - - public function testCheckPasswordLength() - { - $encoder = new PlaintextPasswordEncoder(); - - $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt')); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php deleted file mode 100644 index 4bae5f89f35bc..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; -use Symfony\Component\Security\Core\Exception\BadCredentialsException; - -/** - * @group legacy - */ -class SodiumPasswordEncoderTest extends TestCase -{ - protected function setUp(): void - { - if (!SodiumPasswordEncoder::isSupported()) { - $this->markTestSkipped('Libsodium is not available.'); - } - } - - public function testValidation() - { - $encoder = new SodiumPasswordEncoder(); - $result = $encoder->encodePassword('password', null); - $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); - $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); - $this->assertFalse($encoder->isPasswordValid($result, '', null)); - } - - public function testBCryptValidation() - { - $encoder = new SodiumPasswordEncoder(); - $this->assertTrue($encoder->isPasswordValid('$2y$04$M8GDODMoGQLQRpkYCdoJh.lbiZPee3SZI32RcYK49XYTolDGwoRMm', 'abc', null)); - } - - public function testNonArgonValidation() - { - $encoder = new SodiumPasswordEncoder(); - $this->assertTrue($encoder->isPasswordValid('$5$abcdefgh$ZLdkj8mkc2XVSrPVjskDAgZPGjtj1VGVaa1aUkrMTU/', 'password', null)); - $this->assertFalse($encoder->isPasswordValid('$5$abcdefgh$ZLdkj8mkc2XVSrPVjskDAgZPGjtj1VGVaa1aUkrMTU/', 'anotherPassword', null)); - $this->assertTrue($encoder->isPasswordValid('$6$abcdefgh$yVfUwsw5T.JApa8POvClA1pQ5peiq97DUNyXCZN5IrF.BMSkiaLQ5kvpuEm/VQ1Tvh/KV2TcaWh8qinoW5dhA1', 'password', null)); - $this->assertFalse($encoder->isPasswordValid('$6$abcdefgh$yVfUwsw5T.JApa8POvClA1pQ5peiq97DUNyXCZN5IrF.BMSkiaLQ5kvpuEm/VQ1Tvh/KV2TcaWh8qinoW5dhA1', 'anotherPassword', null)); - } - - public function testEncodePasswordLength() - { - $this->expectException(BadCredentialsException::class); - $encoder = new SodiumPasswordEncoder(); - $encoder->encodePassword(str_repeat('a', 4097), 'salt'); - } - - public function testCheckPasswordLength() - { - $encoder = new SodiumPasswordEncoder(); - $result = $encoder->encodePassword(str_repeat('a', 4096), null); - $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 4097), null)); - $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 4096), null)); - } - - public function testUserProvidedSaltIsNotUsed() - { - $encoder = new SodiumPasswordEncoder(); - $result = $encoder->encodePassword('password', 'salt'); - $this->assertTrue($encoder->isPasswordValid($result, 'password', 'anotherSalt')); - } - - public function testNeedsRehash() - { - $encoder = new SodiumPasswordEncoder(4, 11000); - - $this->assertTrue($encoder->needsRehash('dummyhash')); - - $hash = $encoder->encodePassword('foo', 'salt'); - $this->assertFalse($encoder->needsRehash($hash)); - - $encoder = new SodiumPasswordEncoder(5, 11000); - $this->assertTrue($encoder->needsRehash($hash)); - } -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php b/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php deleted file mode 100644 index 3764038e9a9d3..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; - -/** - * @group legacy - */ -interface TestPasswordEncoderInterface extends PasswordEncoderInterface -{ - public function needsRehash(string $encoded): bool; -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/UserPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/UserPasswordEncoderTest.php deleted file mode 100644 index 6f52fbf1b22d9..0000000000000 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/UserPasswordEncoderTest.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Tests\Encoder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; -use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; -use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder; -use Symfony\Component\Security\Core\User\User; -use Symfony\Component\Security\Core\User\UserInterface; - -/** - * @group legacy - */ -class UserPasswordEncoderTest extends TestCase -{ - public function testEncodePassword() - { - $userMock = $this->createMock(UserInterface::class); - $userMock->expects($this->any()) - ->method('getSalt') - ->willReturn('userSalt'); - - $mockEncoder = $this->createMock(PasswordEncoderInterface::class); - $mockEncoder->expects($this->any()) - ->method('encodePassword') - ->with($this->equalTo('plainPassword'), $this->equalTo('userSalt')) - ->willReturn('encodedPassword'); - - $mockEncoderFactory = $this->createMock(EncoderFactoryInterface::class); - $mockEncoderFactory->expects($this->any()) - ->method('getEncoder') - ->with($this->equalTo($userMock)) - ->willReturn($mockEncoder); - - $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory); - - $encoded = $passwordEncoder->encodePassword($userMock, 'plainPassword'); - $this->assertEquals('encodedPassword', $encoded); - } - - public function testIsPasswordValid() - { - $userMock = $this->createMock(UserInterface::class); - $userMock->expects($this->any()) - ->method('getSalt') - ->willReturn('userSalt'); - $userMock->expects($this->any()) - ->method('getPassword') - ->willReturn('encodedPassword'); - - $mockEncoder = $this->createMock(PasswordEncoderInterface::class); - $mockEncoder->expects($this->any()) - ->method('isPasswordValid') - ->with($this->equalTo('encodedPassword'), $this->equalTo('plainPassword'), $this->equalTo('userSalt')) - ->willReturn(true); - - $mockEncoderFactory = $this->createMock(EncoderFactoryInterface::class); - $mockEncoderFactory->expects($this->any()) - ->method('getEncoder') - ->with($this->equalTo($userMock)) - ->willReturn($mockEncoder); - - $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory); - - $isValid = $passwordEncoder->isPasswordValid($userMock, 'plainPassword'); - $this->assertTrue($isValid); - } - - public function testNeedsRehash() - { - $user = new User('username', null); - $encoder = new NativePasswordEncoder(4, 20000, 4); - - $mockEncoderFactory = $this->createMock(EncoderFactoryInterface::class); - $mockEncoderFactory->expects($this->any()) - ->method('getEncoder') - ->with($user) - ->will($this->onConsecutiveCalls($encoder, $encoder, new NativePasswordEncoder(5, 20000, 5), $encoder)); - - $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory); - - $user->setPassword($passwordEncoder->encodePassword($user, 'foo', 'salt')); - $this->assertFalse($passwordEncoder->needsRehash($user)); - $this->assertTrue($passwordEncoder->needsRehash($user)); - $this->assertFalse($passwordEncoder->needsRehash($user)); - } -} diff --git a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php index 7fb653c46deea..e0230da0f96aa 100644 --- a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php +++ b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php @@ -13,8 +13,6 @@ use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; -use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -68,9 +66,9 @@ public function validate(mixed $password, Constraint $constraint) trigger_deprecation('symfony/security-core', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); } - $hasher = $this->hasherFactory instanceof EncoderFactoryInterface ? $this->hasherFactory->getEncoder($user) : $this->hasherFactory->getPasswordHasher($user); + $hasher = $this->hasherFactory->getPasswordHasher($user); - if (null === $user->getPassword() || !($hasher instanceof PasswordEncoderInterface ? $hasher->isPasswordValid($user->getPassword(), $password, $user->getSalt()) : $hasher->verify($user->getPassword(), $password, $user->getSalt()))) { + if (null === $user->getPassword() || !$hasher->verify($user->getPassword(), $password, $user->getSalt())) { $this->context->addViolation($constraint->message); } } diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index e84a4c6a42ada..e5fea5b509877 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -14,7 +14,6 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; @@ -53,19 +52,14 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface /** * @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener * @param string $providerKey The provider (i.e. firewall) key - * @param UserPasswordHasherInterface $passwordHasher */ - public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, $passwordHasher = null) + public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordHasherInterface $passwordHasher = null) { $this->guardAuthenticators = $guardAuthenticators; $this->userProvider = $userProvider; $this->providerKey = $providerKey; $this->userChecker = $userChecker; $this->passwordHasher = $passwordHasher; - - if ($passwordHasher instanceof UserPasswordEncoderInterface) { - trigger_deprecation('symfony/security-core', '5.3', sprintf('Passing a "%s" instance to the "%s" constructor is deprecated, use "%s" instead.', UserPasswordEncoderInterface::class, __CLASS__, UserPasswordHasherInterface::class)); - } } /** @@ -140,12 +134,7 @@ private function authenticateViaGuard(AuthenticatorInterface $guardAuthenticator throw new BadCredentialsException(sprintf('Authentication failed because "%s::checkCredentials()" did not return true.', get_debug_type($guardAuthenticator))); } if ($this->userProvider instanceof PasswordUpgraderInterface && $guardAuthenticator instanceof PasswordAuthenticatedInterface && null !== $this->passwordHasher && (null !== $password = $guardAuthenticator->getPassword($token->getCredentials())) && $this->passwordHasher->needsRehash($user)) { - if ($this->passwordHasher instanceof UserPasswordEncoderInterface) { - // @deprecated since Symfony 5.3 - $this->userProvider->upgradePassword($user, $this->passwordHasher->encodePassword($user, $password)); - } else { - $this->userProvider->upgradePassword($user, $this->passwordHasher->hashPassword($user, $password)); - } + $this->userProvider->upgradePassword($user, $this->passwordHasher->hashPassword($user, $password)); } $this->userChecker->checkPostAuth($user); diff --git a/src/Symfony/Component/Security/Http/EventListener/CheckCredentialsListener.php b/src/Symfony/Component/Security/Http/EventListener/CheckCredentialsListener.php index 527abe0cd211a..21406f058c1cf 100644 --- a/src/Symfony/Component/Security/Http/EventListener/CheckCredentialsListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/CheckCredentialsListener.php @@ -13,7 +13,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; @@ -72,15 +71,8 @@ public function checkPassport(CheckPassportEvent $event): void trigger_deprecation('symfony/security-http', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); } - // @deprecated since Symfony 5.3 - if ($this->hasherFactory instanceof EncoderFactoryInterface) { - if (!$this->hasherFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $salt)) { - throw new BadCredentialsException('The presented password is invalid.'); - } - } else { - if (!$this->hasherFactory->getPasswordHasher($user)->verify($user->getPassword(), $presentedPassword, $salt)) { - throw new BadCredentialsException('The presented password is invalid.'); - } + if (!$this->hasherFactory->getPasswordHasher($user)->verify($user->getPassword(), $presentedPassword, $salt)) { + throw new BadCredentialsException('The presented password is invalid.'); } $badge->markResolved(); diff --git a/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php b/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php index 96c97fd228733..0b15284f62d62 100644 --- a/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php @@ -14,7 +14,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\PasswordHasher\PasswordHasherInterface; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; @@ -55,7 +54,7 @@ public function onLoginSuccess(LoginSuccessEvent $event): void return; } - $passwordHasher = $this->hasherFactory instanceof EncoderFactoryInterface ? $this->hasherFactory->getEncoder($user) : $this->hasherFactory->getPasswordHasher($user); + $passwordHasher = $this->hasherFactory->getPasswordHasher($user); if (!$passwordHasher->needsRehash($user->getPassword())) { return; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy