vendor/symfony/security-core/Encoder/EncoderFactory.php line 80

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Security\Core\Encoder;
  11. /**
  12.  * A generic encoder factory implementation.
  13.  *
  14.  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  15.  */
  16. class EncoderFactory implements EncoderFactoryInterface
  17. {
  18.     private $encoders;
  19.     public function __construct(array $encoders)
  20.     {
  21.         $this->encoders $encoders;
  22.     }
  23.     /**
  24.      * {@inheritdoc}
  25.      */
  26.     public function getEncoder($user)
  27.     {
  28.         $encoderKey null;
  29.         if ($user instanceof EncoderAwareInterface && (null !== $encoderName $user->getEncoderName())) {
  30.             if (!\array_key_exists($encoderName$this->encoders)) {
  31.                 throw new \RuntimeException(sprintf('The encoder "%s" was not configured.'$encoderName));
  32.             }
  33.             $encoderKey $encoderName;
  34.         } else {
  35.             foreach ($this->encoders as $class => $encoder) {
  36.                 if ((\is_object($user) && $user instanceof $class) || (!\is_object($user) && (is_subclass_of($user$class) || $user == $class))) {
  37.                     $encoderKey $class;
  38.                     break;
  39.                 }
  40.             }
  41.         }
  42.         if (null === $encoderKey) {
  43.             throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', \is_object($user) ? \get_class($user) : $user));
  44.         }
  45.         if (!$this->encoders[$encoderKey] instanceof PasswordEncoderInterface) {
  46.             $this->encoders[$encoderKey] = $this->createEncoder($this->encoders[$encoderKey]);
  47.         }
  48.         return $this->encoders[$encoderKey];
  49.     }
  50.     /**
  51.      * Creates the actual encoder instance.
  52.      *
  53.      * @return PasswordEncoderInterface
  54.      *
  55.      * @throws \InvalidArgumentException
  56.      */
  57.     private function createEncoder(array $config)
  58.     {
  59.         if (isset($config['algorithm'])) {
  60.             $config $this->getEncoderConfigFromAlgorithm($config);
  61.         }
  62.         if (!isset($config['class'])) {
  63.             throw new \InvalidArgumentException(sprintf('"class" must be set in %s.'json_encode($config)));
  64.         }
  65.         if (!isset($config['arguments'])) {
  66.             throw new \InvalidArgumentException(sprintf('"arguments" must be set in %s.'json_encode($config)));
  67.         }
  68.         $reflection = new \ReflectionClass($config['class']);
  69.         return $reflection->newInstanceArgs($config['arguments']);
  70.     }
  71.     private function getEncoderConfigFromAlgorithm($config)
  72.     {
  73.         if ('auto' === $config['algorithm']) {
  74.             $config['algorithm'] = SodiumPasswordEncoder::isSupported() ? 'sodium' 'native';
  75.         }
  76.         switch ($config['algorithm']) {
  77.             case 'plaintext':
  78.                 return [
  79.                     'class' => PlaintextPasswordEncoder::class,
  80.                     'arguments' => [$config['ignore_case']],
  81.                 ];
  82.             case 'pbkdf2':
  83.                 return [
  84.                     'class' => Pbkdf2PasswordEncoder::class,
  85.                     'arguments' => [
  86.                         $config['hash_algorithm'],
  87.                         $config['encode_as_base64'],
  88.                         $config['iterations'],
  89.                         $config['key_length'],
  90.                     ],
  91.                 ];
  92.             /* @deprecated since Symfony 4.3 */
  93.             case 'bcrypt':
  94.                 return [
  95.                     'class' => BCryptPasswordEncoder::class,
  96.                     'arguments' => [$config['cost']],
  97.                 ];
  98.             case 'native':
  99.                 return [
  100.                     'class' => NativePasswordEncoder::class,
  101.                     'arguments' => [
  102.                         $config['time_cost'] ?? null,
  103.                         (($config['memory_cost'] ?? 0) << 10) ?: null,
  104.                         $config['cost'] ?? null,
  105.                     ],
  106.                 ];
  107.             case 'sodium':
  108.                 return [
  109.                     'class' => SodiumPasswordEncoder::class,
  110.                     'arguments' => [
  111.                         $config['time_cost'] ?? null,
  112.                         (($config['memory_cost'] ?? 0) << 10) ?: null,
  113.                     ],
  114.                 ];
  115.             /* @deprecated since Symfony 4.3 */
  116.             case 'argon2i':
  117.                 return [
  118.                     'class' => Argon2iPasswordEncoder::class,
  119.                     'arguments' => [
  120.                         $config['memory_cost'],
  121.                         $config['time_cost'],
  122.                         $config['threads'],
  123.                     ],
  124.                 ];
  125.         }
  126.         return [
  127.             'class' => MessageDigestPasswordEncoder::class,
  128.             'arguments' => [
  129.                 $config['algorithm'],
  130.                 $config['encode_as_base64'],
  131.                 $config['iterations'],
  132.             ],
  133.         ];
  134.     }
  135. }