From 7903a46dfac78ab3f6aa29338a13691f738baf2a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 4 Sep 2016 10:34:53 +0200 Subject: [PATCH] [Security] Allow run-time configuration of hash algo --- .../DependencyInjection/SecurityExtension.php | 11 +---- .../CompleteConfigurationTest.php | 18 +++++++-- .../Bundle/SecurityBundle/composer.json | 2 +- .../Security/Core/Encoder/EncoderFactory.php | 40 +++++++++++++++++++ 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 51a234a288388..4398a2a36d433 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -493,15 +493,8 @@ private function createEncoder($config, ContainerBuilder $container) ); } - // message digest encoder - return array( - 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', - 'arguments' => array( - $config['algorithm'], - $config['encode_as_base64'], - $config['iterations'], - ), - ); + // run-time configured encoder + return $config; } // Parses user providers and returns an array of their ids diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index af293a7b633ff..a0dc39a11629e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -191,12 +191,22 @@ public function testEncoders() 'arguments' => array(false), ), 'JMS\FooBundle\Entity\User2' => array( - 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', - 'arguments' => array('sha1', false, 5), + 'algorithm' => 'sha1', + 'encode_as_base64' => false, + 'iterations' => 5, + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'cost' => 13, ), 'JMS\FooBundle\Entity\User3' => array( - 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', - 'arguments' => array('md5', true, 5000), + 'algorithm' => 'md5', + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'encode_as_base64' => true, + 'iterations' => 5000, + 'cost' => 13, ), 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), 'JMS\FooBundle\Entity\User5' => array( diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 495c670e7d7b8..4d588399df477 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.5.9", - "symfony/security": "~3.1,>=3.1.2", + "symfony/security": "~3.2", "symfony/http-kernel": "~3.1", "symfony/polyfill-php70": "~1.0" }, diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index 0568d41c9b6d7..7794b2f4dbcc1 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -69,6 +69,9 @@ public function getEncoder($user) */ private function createEncoder(array $config) { + if (isset($config['algorithm'])) { + $config = $this->getEncoderConfigFromAlgorithm($config); + } if (!isset($config['class'])) { throw new \InvalidArgumentException(sprintf('"class" must be set in %s.', json_encode($config))); } @@ -80,4 +83,41 @@ private function createEncoder(array $config) return $reflection->newInstanceArgs($config['arguments']); } + + private function getEncoderConfigFromAlgorithm($config) + { + switch ($config['algorithm']) { + case 'plaintext': + return array( + 'class' => PlaintextPasswordEncoder::class, + 'arguments' => array($config['ignore_case']), + ); + + case 'pbkdf2': + return array( + 'class' => Pbkdf2PasswordEncoder::class, + 'arguments' => array( + $config['hash_algorithm'], + $config['encode_as_base64'], + $config['iterations'], + $config['key_length'], + ), + ); + + case 'bcrypt': + return array( + 'class' => BCryptPasswordEncoder::class, + 'arguments' => array($config['cost']), + ); + } + + return array( + 'class' => MessageDigestPasswordEncoder::class, + 'arguments' => array( + $config['algorithm'], + $config['encode_as_base64'], + $config['iterations'], + ), + ); + } }