Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b5a47df

Browse files
feature #34020 [Security] Allow to stick to a specific password hashing algorithm (chalasr)
This PR was merged into the 4.4 branch. Discussion ---------- [Security] Allow to stick to a specific password hashing algorithm | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #33054 | License | MIT | Doc PR | todo Allows using `argon2i`, `argon2id` and `bcrypt`. Commits ------- 6712d1e [Security] Allow to set a fixed algorithm
2 parents 60a4d8d + 6712d1e commit b5a47df

File tree

14 files changed

+139
-81
lines changed

14 files changed

+139
-81
lines changed

UPGRADE-4.3.md

Lines 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

Lines 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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ CHANGELOG
22
=========
33

44
4.4.0
5+
-----
56

6-
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
7+
* Added new `argon2id` encoder, undeprecated the `bcrypt` and `argon2i` ones (using `auto` is still recommended by default.)
8+
* Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories.
79

810
4.3.0
911
-----
@@ -14,7 +16,6 @@ CHANGELOG
1416
option is deprecated and will be disabled in Symfony 5.0. This affects to cookies
1517
with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie`
1618
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
1819

1920
4.2.0
2021
-----

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

Lines changed: 24 additions & 22 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;
@@ -538,34 +537,37 @@ private function createEncoder(array $config)
538537

539538
// bcrypt encoder
540539
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);
540+
$config['algorithm'] = 'native';
541+
$config['native_algorithm'] = PASSWORD_BCRYPT;
542542

543-
return [
544-
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
545-
'arguments' => [$config['cost'] ?? 13],
546-
];
543+
return $this->createEncoder($config);
547544
}
548545

549546
// Argon2i encoder
550547
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);
548+
if (SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
549+
$config['algorithm'] = 'sodium';
550+
} elseif (\defined('PASSWORD_ARGON2I')) {
551+
$config['algorithm'] = 'native';
552+
$config['native_algorithm'] = PASSWORD_ARGON2I;
553+
} else {
554+
throw new InvalidConfigurationException(sprintf('Algorithm "argon2i" is not available. Either use %s"auto" or upgrade to PHP 7.2+ instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? '"argon2id", ' : ''));
555+
}
552556

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.');
556-
}
557+
return $this->createEncoder($config);
558+
}
557559

558-
throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use "auto" instead.');
560+
if ('argon2id' === $config['algorithm']) {
561+
if (($hasSodium = SodiumPasswordEncoder::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
562+
$config['algorithm'] = 'sodium';
563+
} elseif (\defined('PASSWORD_ARGON2ID')) {
564+
$config['algorithm'] = 'native';
565+
$config['native_algorithm'] = PASSWORD_ARGON2ID;
566+
} else {
567+
throw new InvalidConfigurationException(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", ' : ''));
559568
}
560569

561-
return [
562-
'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder',
563-
'arguments' => [
564-
$config['memory_cost'],
565-
$config['time_cost'],
566-
$config['threads'],
567-
],
568-
];
570+
return $this->createEncoder($config);
569571
}
570572

571573
if ('native' === $config['algorithm']) {
@@ -574,8 +576,8 @@ private function createEncoder(array $config)
574576
'arguments' => [
575577
$config['time_cost'],
576578
(($config['memory_cost'] ?? 0) << 10) ?: null,
577-
$config['cost'],
578-
],
579+
$config['cost']
580+
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
579581
];
580582
}
581583

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

Lines changed: 6 additions & 15 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
@@ -377,14 +377,9 @@ public function testEncodersWithLibsodium()
377377
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
378378
}
379379

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

@@ -429,19 +424,15 @@ public function testEncodersWithArgon2i()
429424
'arguments' => [8, 102400, 15],
430425
],
431426
'JMS\FooBundle\Entity\User7' => [
432-
'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder',
433-
'arguments' => [256, 1, 2],
427+
'class' => $sodium ? SodiumPasswordEncoder::class : NativePasswordEncoder::class,
428+
'arguments' => $sodium ? [256, 1] : [1, 262144, null, \PASSWORD_ARGON2I],
434429
],
435430
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
436431
}
437432

438-
/**
439-
* @group legacy
440-
*/
441433
public function testEncodersWithBCrypt()
442434
{
443435
$container = $this->getContainer('bcrypt_encoder');
444-
445436
$this->assertEquals([[
446437
'JMS\FooBundle\Entity\User1' => [
447438
'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder',
@@ -481,8 +472,8 @@ public function testEncodersWithBCrypt()
481472
'arguments' => [8, 102400, 15],
482473
],
483474
'JMS\FooBundle\Entity\User7' => [
484-
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
485-
'arguments' => [15],
475+
'class' => NativePasswordEncoder::class,
476+
'arguments' => [null, null, 15, \PASSWORD_BCRYPT],
486477
],
487478
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
488479
}

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

Lines 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
]);

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

Lines 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>

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

Lines 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

src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand;
1616
use Symfony\Component\Console\Application as ConsoleApplication;
1717
use Symfony\Component\Console\Tester\CommandTester;
18-
use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder;
19-
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
2018
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
2119
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
2220
use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder;
@@ -55,9 +53,6 @@ public function testEncodeNoPasswordNoInteraction()
5553
$this->assertEquals($statusCode, 1);
5654
}
5755

58-
/**
59-
* @group legacy
60-
*/
6156
public function testEncodePasswordBcrypt()
6257
{
6358
$this->setupBcrypt();
@@ -70,18 +65,15 @@ public function testEncodePasswordBcrypt()
7065
$output = $this->passwordEncoderCommandTester->getDisplay();
7166
$this->assertStringContainsString('Password encoding succeeded', $output);
7267

73-
$encoder = new BCryptPasswordEncoder(17);
68+
$encoder = new NativePasswordEncoder(null, null, 17, PASSWORD_BCRYPT);
7469
preg_match('# Encoded password\s{1,}([\w+\/$.]+={0,2})\s+#', $output, $matches);
7570
$hash = $matches[1];
7671
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
7772
}
7873

79-
/**
80-
* @group legacy
81-
*/
8274
public function testEncodePasswordArgon2i()
8375
{
84-
if (!Argon2iPasswordEncoder::isSupported()) {
76+
if (!($sodium = SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
8577
$this->markTestSkipped('Argon2i algorithm not available.');
8678
}
8779
$this->setupArgon2i();
@@ -94,7 +86,28 @@ public function testEncodePasswordArgon2i()
9486
$output = $this->passwordEncoderCommandTester->getDisplay();
9587
$this->assertStringContainsString('Password encoding succeeded', $output);
9688

97-
$encoder = new Argon2iPasswordEncoder();
89+
$encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, PASSWORD_ARGON2I);
90+
preg_match('# Encoded password\s+(\$argon2i?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches);
91+
$hash = $matches[1];
92+
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
93+
}
94+
95+
public function testEncodePasswordArgon2id()
96+
{
97+
if (!($sodium = (SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'))) && !\defined('PASSWORD_ARGON2ID')) {
98+
$this->markTestSkipped('Argon2id algorithm not available.');
99+
}
100+
$this->setupArgon2id();
101+
$this->passwordEncoderCommandTester->execute([
102+
'command' => 'security:encode-password',
103+
'password' => 'password',
104+
'user-class' => 'Custom\Class\Argon2id\User',
105+
], ['interactive' => false]);
106+
107+
$output = $this->passwordEncoderCommandTester->getDisplay();
108+
$this->assertStringContainsString('Password encoding succeeded', $output);
109+
110+
$encoder = $sodium ? new SodiumPasswordEncoder() : new NativePasswordEncoder(null, null, null, PASSWORD_ARGON2ID);
98111
preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches);
99112
$hash = $matches[1];
100113
$this->assertTrue($encoder->isPasswordValid($hash, 'password', null));
@@ -195,12 +208,9 @@ public function testEncodePasswordNativeOutput()
195208
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
196209
}
197210

198-
/**
199-
* @group legacy
200-
*/
201211
public function testEncodePasswordArgon2iOutput()
202212
{
203-
if (!Argon2iPasswordEncoder::isSupported()) {
213+
if (!(SodiumPasswordEncoder::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2I')) {
204214
$this->markTestSkipped('Argon2i algorithm not available.');
205215
}
206216

@@ -214,6 +224,22 @@ public function testEncodePasswordArgon2iOutput()
214224
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
215225
}
216226

227+
public function testEncodePasswordArgon2idOutput()
228+
{
229+
if (!(SodiumPasswordEncoder::isSupported() && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) && !\defined('PASSWORD_ARGON2ID')) {
230+
$this->markTestSkipped('Argon2id algorithm not available.');
231+
}
232+
233+
$this->setupArgon2id();
234+
$this->passwordEncoderCommandTester->execute([
235+
'command' => 'security:encode-password',
236+
'password' => 'p@ssw0rd',
237+
'user-class' => 'Custom\Class\Argon2id\User',
238+
], ['interactive' => false]);
239+
240+
$this->assertStringNotContainsString(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay());
241+
}
242+
217243
public function testEncodePasswordSodiumOutput()
218244
{
219245
if (!SodiumPasswordEncoder::isSupported()) {
@@ -317,6 +343,19 @@ private function setupArgon2i()
317343
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
318344
}
319345

346+
private function setupArgon2id()
347+
{
348+
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
349+
$kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']);
350+
$kernel->boot();
351+
352+
$application = new Application($kernel);
353+
354+
$passwordEncoderCommand = $application->get('security:encode-password');
355+
356+
$this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand);
357+
}
358+
320359
private function setupBcrypt()
321360
{
322361
putenv('COLUMNS='.(119 + \strlen(PHP_EOL)));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
imports:
2+
- { resource: config.yml }
3+
4+
security:
5+
encoders:
6+
Custom\Class\Argon2id\User:
7+
algorithm: argon2id

src/Symfony/Component/Security/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ CHANGELOG
1313
* Marked all dispatched event classes as `@final`
1414
* Deprecated returning a non-boolean value when implementing `Guard\AuthenticatorInterface::checkCredentials()`.
1515
* Deprecated passing more than one attribute to `AccessDecisionManager::decide()` and `AuthorizationChecker::isGranted()`
16+
* Added new `argon2id` encoder, undeprecated the `bcrypt` and `argon2i` ones (using `auto` is still recommended by default.)
1617

1718
4.3.0
1819
-----

0 commit comments

Comments
 (0)