Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3e7cef8

Browse filesBrowse files
committed
[Security] Allow to configure a specific password hashing algorithm
1 parent b54997d commit 3e7cef8
Copy full SHA for 3e7cef8

18 files changed

+366
-73
lines changed

‎UPGRADE-4.3.md

Copy file name to clipboardExpand all lines: UPGRADE-4.3.md
-5Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,6 @@ Security
209209
* Not implementing the methods `__serialize` and `__unserialize` in classes implementing
210210
the `TokenInterface` is deprecated
211211

212-
SecurityBundle
213-
--------------
214-
215-
* Configuring encoders using `argon2i` or `bcrypt` as algorithm has been deprecated, use `auto` instead.
216-
217212
TwigBridge
218213
----------
219214

‎UPGRADE-5.0.md

Copy file name to clipboardExpand all lines: UPGRADE-5.0.md
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,6 @@ SecurityBundle
509509
changed to underscores.
510510
Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore).
511511
After: `my-cookie` deletes the `my-cookie` cookie (with a dash).
512-
* Configuring encoders using `argon2i` or `bcrypt` as algorithm is not supported anymore, use `auto` instead.
513512

514513
Serializer
515514
----------

‎src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ CHANGELOG
33

44
4.4.0
55

6+
* Added `migrate_from` option to encoders configuration.
67
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
78

89
4.3.0
@@ -14,7 +15,6 @@ CHANGELOG
1415
option is deprecated and will be disabled in Symfony 5.0. This affects to cookies
1516
with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie`
1617
name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore).
17-
* Deprecated configuring encoders using `argon2i` as algorithm, use `auto` instead
1818

1919
4.2.0
2020
-----

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode)
394394
->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end()
395395
->children()
396396
->scalarNode('algorithm')->cannotBeEmpty()->end()
397+
->arrayNode('migrating_from')
398+
->prototype('scalar')->end()
399+
->beforeNormalization()->castToArray()->end()
400+
->end()
397401
->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()
398402
->scalarNode('key_length')->defaultValue(40)->end()
399403
->booleanNode('ignore_case')->defaultFalse()->end()

‎src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+57-14Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use Symfony\Component\DependencyInjection\Reference;
2929
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
3030
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
31-
use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder;
3231
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
3332
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
3433
use Symfony\Component\Security\Core\User\UserProviderInterface;
@@ -513,6 +512,10 @@ private function createEncoder(array $config)
513512
return new Reference($config['id']);
514513
}
515514

515+
if ($config['migrating_from'] ?? false) {
516+
return $config;
517+
}
518+
516519
// plaintext encoder
517520
if ('plaintext' === $config['algorithm']) {
518521
$arguments = [$config['ignore_case']];
@@ -538,32 +541,72 @@ private function createEncoder(array $config)
538541

539542
// bcrypt encoder
540543
if ('bcrypt' === $config['algorithm']) {
541-
@trigger_error('Configuring an encoder with "bcrypt" as algorithm is deprecated since Symfony 4.3, use "auto" instead.', E_USER_DEPRECATED);
542-
543544
return [
544-
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
545-
'arguments' => [$config['cost'] ?? 13],
545+
'class' => NativePasswordEncoder::class,
546+
'arguments' => [
547+
$config['time_cost'] ?? null,
548+
(($config['memory_cost'] ?? 0) << 10) ?: null,
549+
$config['cost'] ?? null,
550+
\PASSWORD_BCRYPT,
551+
],
546552
];
547553
}
548554

549555
// Argon2i encoder
550556
if ('argon2i' === $config['algorithm']) {
551-
@trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead.', E_USER_DEPRECATED);
557+
if (SodiumPasswordEncoder::isSupported() && !($hasSodiumArgon2id = \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'))) {
558+
return [
559+
'class' => SodiumPasswordEncoder::class,
560+
'arguments' => [
561+
$config['time_cost'] ?? null,
562+
(($config['memory_cost'] ?? 0) << 10) ?: null,
563+
],
564+
];
565+
}
552566

553-
if (!Argon2iPasswordEncoder::isSupported()) {
554-
if (\extension_loaded('sodium') && !\defined('SODIUM_CRYPTO_PWHASH_SALTBYTES')) {
555-
throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use "auto" instead.');
567+
if (!\defined('PASSWORD_ARGON2I')) {
568+
if ($hasSodiumArgon2id ?? false) {
569+
throw new InvalidConfigurationException('Algorithm "argon2i" is not available. You should either use "argon2id", downgrade your sodium extension or use a different encoder.');
556570
}
571+
throw new InvalidConfigurationException('Algorithm "argon2i" is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
572+
}
557573

558-
throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use "auto" instead.');
574+
return [
575+
'class' => NativePasswordEncoder::class,
576+
'arguments' => [
577+
$config['time_cost'] ?? null,
578+
(($config['memory_cost'] ?? 0) << 10) ?: null,
579+
$config['cost'] ?? null,
580+
\PASSWORD_ARGON2I,
581+
],
582+
];
583+
}
584+
585+
if ('argon2id' === $config['algorithm']) {
586+
if (($hasSodium = SodiumPasswordEncoder::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
587+
return [
588+
'class' => SodiumPasswordEncoder::class,
589+
'arguments' => [
590+
$config['time_cost'] ?? null,
591+
(($config['memory_cost'] ?? 0) << 10) ?: null,
592+
],
593+
];
594+
}
595+
596+
if (!\defined('PASSWORD_ARGON2ID')) {
597+
if (\defined('PASSWORD_ARGON2I') || $hasSodium) {
598+
throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. You can either use "argon2i", upgrade to PHP 7.3+, %s sodium extension or use a different encoder.', $hasSodium ? 'upgrade your' : 'install the'));
599+
}
600+
throw new InvalidConfigurationException(sprintf('Algorithm "argon2id" is not available. You should either %s sodium extension, upgrade to PHP 7.3+ or use a different encoder.', $hasSodium ? 'upgrade your' : 'install the'));
559601
}
560602

561603
return [
562-
'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder',
604+
'class' => NativePasswordEncoder::class,
563605
'arguments' => [
564-
$config['memory_cost'],
565-
$config['time_cost'],
566-
$config['threads'],
606+
$config['time_cost'] ?? null,
607+
(($config['memory_cost'] ?? 0) << 10) ?: null,
608+
$config['cost'] ?? null,
609+
\PASSWORD_ARGON2ID,
567610
],
568611
];
569612
}

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
+79-14Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\Reference;
2020
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
21-
use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder;
21+
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
2222
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
2323

2424
abstract class CompleteConfigurationTest extends TestCase
@@ -287,6 +287,7 @@ public function testEncoders()
287287
'memory_cost' => null,
288288
'time_cost' => null,
289289
'threads' => null,
290+
'migrating_from' => [],
290291
],
291292
'JMS\FooBundle\Entity\User3' => [
292293
'algorithm' => 'md5',
@@ -299,6 +300,7 @@ public function testEncoders()
299300
'memory_cost' => null,
300301
'time_cost' => null,
301302
'threads' => null,
303+
'migrating_from' => [],
302304
],
303305
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
304306
'JMS\FooBundle\Entity\User5' => [
@@ -320,6 +322,7 @@ public function testEncoders()
320322
'memory_cost' => null,
321323
'time_cost' => null,
322324
'threads' => null,
325+
'migrating_from' => [],
323326
],
324327
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
325328
}
@@ -348,6 +351,7 @@ public function testEncodersWithLibsodium()
348351
'memory_cost' => null,
349352
'time_cost' => null,
350353
'threads' => null,
354+
'migrating_from' => [],
351355
],
352356
'JMS\FooBundle\Entity\User3' => [
353357
'algorithm' => 'md5',
@@ -360,6 +364,7 @@ public function testEncodersWithLibsodium()
360364
'memory_cost' => null,
361365
'time_cost' => null,
362366
'threads' => null,
367+
'migrating_from' => [],
363368
],
364369
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
365370
'JMS\FooBundle\Entity\User5' => [
@@ -377,14 +382,9 @@ public function testEncodersWithLibsodium()
377382
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
378383
}
379384

380-
/**
381-
* @group legacy
382-
*
383-
* @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead.
384-
*/
385385
public function testEncodersWithArgon2i()
386386
{
387-
if (!Argon2iPasswordEncoder::isSupported()) {
387+
if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
388388
$this->markTestSkipped('Argon2i algorithm is not supported.');
389389
}
390390

@@ -406,6 +406,7 @@ public function testEncodersWithArgon2i()
406406
'memory_cost' => null,
407407
'time_cost' => null,
408408
'threads' => null,
409+
'migrating_from' => [],
409410
],
410411
'JMS\FooBundle\Entity\User3' => [
411412
'algorithm' => 'md5',
@@ -418,6 +419,7 @@ public function testEncodersWithArgon2i()
418419
'memory_cost' => null,
419420
'time_cost' => null,
420421
'threads' => null,
422+
'migrating_from' => [],
421423
],
422424
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
423425
'JMS\FooBundle\Entity\User5' => [
@@ -429,15 +431,76 @@ public function testEncodersWithArgon2i()
429431
'arguments' => [8, 102400, 15],
430432
],
431433
'JMS\FooBundle\Entity\User7' => [
432-
'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder',
433-
'arguments' => [256, 1, 2],
434+
'class' => $sodium ? SodiumPasswordEncoder::class : NativePasswordEncoder::class,
435+
'arguments' => $sodium ? [256, 1] : [1, 262144, null, \PASSWORD_ARGON2I],
436+
],
437+
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
438+
}
439+
440+
public function testMigratingEncoder()
441+
{
442+
if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
443+
$this->markTestSkipped('Argon2i algorithm is not supported.');
444+
}
445+
446+
$container = $this->getContainer('migrating_encoder');
447+
448+
$this->assertEquals([[
449+
'JMS\FooBundle\Entity\User1' => [
450+
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
451+
'arguments' => [false],
452+
],
453+
'JMS\FooBundle\Entity\User2' => [
454+
'algorithm' => 'sha1',
455+
'encode_as_base64' => false,
456+
'iterations' => 5,
457+
'hash_algorithm' => 'sha512',
458+
'key_length' => 40,
459+
'ignore_case' => false,
460+
'cost' => null,
461+
'memory_cost' => null,
462+
'time_cost' => null,
463+
'threads' => null,
464+
'migrating_from' => [],
465+
],
466+
'JMS\FooBundle\Entity\User3' => [
467+
'algorithm' => 'md5',
468+
'hash_algorithm' => 'sha512',
469+
'key_length' => 40,
470+
'ignore_case' => false,
471+
'encode_as_base64' => true,
472+
'iterations' => 5000,
473+
'cost' => null,
474+
'memory_cost' => null,
475+
'time_cost' => null,
476+
'threads' => null,
477+
'migrating_from' => [],
478+
],
479+
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
480+
'JMS\FooBundle\Entity\User5' => [
481+
'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder',
482+
'arguments' => ['sha1', false, 5, 30],
483+
],
484+
'JMS\FooBundle\Entity\User6' => [
485+
'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder',
486+
'arguments' => [8, 102400, 15],
487+
],
488+
'JMS\FooBundle\Entity\User7' => [
489+
'algorithm' => 'argon2i',
490+
'hash_algorithm' => 'sha512',
491+
'key_length' => 40,
492+
'ignore_case' => false,
493+
'encode_as_base64' => true,
494+
'iterations' => 5000,
495+
'cost' => null,
496+
'memory_cost' => 256,
497+
'time_cost' => 1,
498+
'threads' => null,
499+
'migrating_from' => ['bcrypt'],
434500
],
435501
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
436502
}
437503

438-
/**
439-
* @group legacy
440-
*/
441504
public function testEncodersWithBCrypt()
442505
{
443506
$container = $this->getContainer('bcrypt_encoder');
@@ -458,6 +521,7 @@ public function testEncodersWithBCrypt()
458521
'memory_cost' => null,
459522
'time_cost' => null,
460523
'threads' => null,
524+
'migrating_from' => [],
461525
],
462526
'JMS\FooBundle\Entity\User3' => [
463527
'algorithm' => 'md5',
@@ -470,6 +534,7 @@ public function testEncodersWithBCrypt()
470534
'memory_cost' => null,
471535
'time_cost' => null,
472536
'threads' => null,
537+
'migrating_from' => [],
473538
],
474539
'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'),
475540
'JMS\FooBundle\Entity\User5' => [
@@ -481,8 +546,8 @@ public function testEncodersWithBCrypt()
481546
'arguments' => [8, 102400, 15],
482547
],
483548
'JMS\FooBundle\Entity\User7' => [
484-
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
485-
'arguments' => [15],
549+
'class' => NativePasswordEncoder::class,
550+
'arguments' => [null, null, 15, \PASSWORD_BCRYPT],
486551
],
487552
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
488553
}

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
'algorithm' => 'argon2i',
99
'memory_cost' => 256,
1010
'time_cost' => 1,
11-
'threads' => 2,
1211
],
1312
],
1413
]);
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
$this->load('container1.php', $container);
4+
5+
$container->loadFromExtension('security', [
6+
'encoders' => [
7+
'JMS\FooBundle\Entity\User7' => [
8+
'algorithm' => 'argon2i',
9+
'memory_cost' => 256,
10+
'time_cost' => 1,
11+
'migrating_from' => 'bcrypt',
12+
],
13+
],
14+
]);

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2i_encoder.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2i_encoder.xml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</imports>
1111

1212
<sec:config>
13-
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2i" memory_cost="256" time_cost="1" threads="2" />
13+
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2i" memory_cost="256" time_cost="1" />
1414
</sec:config>
1515

1616
</container>
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:sec="http://symfony.com/schema/dic/security"
6+
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
7+
8+
<imports>
9+
<import resource="container1.xml"/>
10+
</imports>
11+
12+
<sec:config>
13+
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2i" memory_cost="256" time_cost="1">
14+
<sec:migrating_from>bcrypt</sec:migrating_from>
15+
</sec:encoder>
16+
</sec:config>
17+
18+
</container>

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2i_encoder.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2i_encoder.yml
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ security:
77
algorithm: argon2i
88
memory_cost: 256
99
time_cost: 1
10-
threads: 2

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.