8000 [Security] Add NativePasswordEncoder by nicolas-grekas · Pull Request #31140 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Security] Add NativePasswordEncoder #31140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion UPGRADE-4.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Security
SecurityBundle
--------------

* Configuring encoders using `argon2i` as algorithm has been deprecated, use `sodium` instead.
* Configuring encoders using `argon2i` as algorithm has been deprecated, use `auto` instead.

TwigBridge
----------
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ CHANGELOG
4.3.0
-----

* Added new encoder types: `auto` (recommended), `native` and `sodium`
* The normalization of the cookie names configured in the `logout.delete_cookies`
option is deprecated and will be disabled in Symfony 5.0. This affects to cookies
with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie`
name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore).
* Deprecated configuring encoders using `argon2i` as algorithm, use `sodium` instead
* Deprecated configuring encoders using `argon2i` as algorithm, use `auto` instead

4.2.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,10 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('encoders')
->example([
'App\Entity\User1' => 'bcrypt',
'App\Entity\User1' => 'auto',
'App\Entity\User2' => [
'algorithm' => 'bcrypt',
'algorithm' => 'auto',
'time_cost' => 8,
'cost' => 13,
],
])
Expand All @@ -416,11 +417,14 @@ private function addEncodersSection(ArrayNodeDefinit 10000 ion $rootNode)
->integerNode('cost')
->min(4)
->max(31)
->defaultValue(13)
->defaultNull()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The defaults belong to the implementation now, not to the configuration.

->end()
->scalarNode('memory_cost')->defaultNull()->end()
->scalarNode('time_cost')->defaultNull()->end()
->scalarNode('threads')->defaultNull()->end()
->scalarNode('threads')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libsodium hardcodes threads to 1, and this makes sense in PHP too.

->defaultNull()
->setDeprecated('The "%path%.%node%" configuration key has no effect since Symfony 4.3 and will be removed in 5.0.')
->end()
->scalarNode('id')->end()
->end()
->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder;
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Controller\UserValueResolver;
Expand Down Expand Up @@ -559,20 +560,20 @@ private function createEncoder($config, ContainerBuilder $container)
if ('bcrypt' === $config['algorithm']) {
return [
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
'arguments' => [$config['cost']],
'arguments' => [$config['cost'] ?? 13],
];
}

// Argon2i encoder
if ('argon2i' === $config['algorithm']) {
@trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead.', E_USER_DEPRECATED);
@trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead.', E_USER_DEPRECATED);

if (!Argon2iPasswordEncoder::isSupported()) {
if (\extension_loaded('sodium') && !\defined('SODIUM_CRYPTO_PWHASH_SALTBYTES')) {
throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use Bcrypt instead.');
throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use "auto" instead.');
}

throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.');
throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use "auto" instead.');
}

return [
Expand All @@ -585,14 +586,28 @@ private function createEncoder($config, ContainerBuilder $container)
];
}

if ('native' === $config['algorithm']) {
return [
'class' => NativePasswordEncoder::class,
'arguments' => [
$config['time_cost'],
(($config['memory_cost'] ?? 0) << 10) ?: null,
Copy link
Member Author
@nicolas-grekas nicolas-grekas Apr 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memory_cost (from password_hash) is in kib but SodiumPasswordEncoder and NativePasswordEncoder accept bytes - this makes the conversion

$config['cost'],
],
];
}

if ('sodium' === $config['algorithm']) {
if (!SodiumPasswordEncoder::isSupported()) {
throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use BCrypt instead.');
throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use "auto" instead.');
}

return [
'class' => SodiumPasswordEncoder::class,
'arguments' => [],
'arguments' => [
$config['time_cost'],
(($config['memory_cost'] ?? 0) << 10) ?: null,
],
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public function testEncoders()
'hash_algorithm' => 'sha512',
'key_length' => 40,
'ignore_case' => false,
'cost' => 1 F41A 3,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -295,7 +295,7 @@ public function testEncoders()
'ignore_case' => false,
'encode_as_base64' => true,
'iterations' => 5000,
'cost' => 13,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -309,6 +309,22 @@ public function testEncoders()
'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder',
'arguments' => [15],
],
'JMS\FooBundle\Entity\User7' => [
'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder',
'arguments' => [8, 102400, 15],
],
'JMS\FooBundle\Entity\User8' => [
'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,
'threads' => null,
],
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
}

Expand All @@ -332,7 +348,7 @@ public function testEncodersWithLibsodium()
'hash_algorithm' => 'sha512',
'key_length' => 40,
'ignore_case' => false,
'cost' => 13,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -344,7 +360,7 @@ public function testEncodersWithLibsodium()
'ignore_case' => false,
'encode_as_base64' => true,
'iterations' => 5000,
'cost' => 13,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -360,15 +376,27 @@ public function testEncodersWithLibsodium()
],
'JMS\FooBundle\Entity\User7' => [
'class' => 'Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder',
'arguments' => [],
'arguments' => [8, 128 * 1024 * 1024],
],
'JMS\FooBundle\Entity\User8' => [
'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,
'threads' => null,
],
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
}

/**
* @group legacy
*
* @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead.
* @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead.
*/
public function testEncodersWithArgon2i()
{
Expand All @@ -390,7 +418,7 @@ public function testEncodersWithArgon2i()
'hash_algorithm' => 'sha512',
'key_length' => 40,
'ignore_case' => false,
'cost' => 13,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -402,7 +430,7 @@ public function testEncodersWithArgon2i()
'ignore_case' => false,
'encode_as_base64' => true,
'iterations' => 5000,
'cost' => 13,
'cost' => null,
'memory_cost' => null,
'time_cost' => null,
'threads' => null,
Expand All @@ -420,6 +448,18 @@ public function testEncodersWithArgon2i()
'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder',
'arguments' => [256, 1, 2],
],
'JMS\FooBundle\Entity\User8' => [
'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,
'threads' => null,
],
]], $container->getDefinition('security.encoder_factory.generic')->getArguments());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
'algorithm' => 'bcrypt',
'cost' => 15,
],
'JMS\FooBundle\Entity\User7' => [
'algorithm' => 'native',
'time_cost' => 8,
'memory_cost' => 100,
'cost' => 15,
],
'JMS\FooBundle\Entity\User8' => [
'algorithm' => 'auto',
],
],
'providers' => [
'default' => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
'encoders' => [
'JMS\FooBundle\Entity\User7' => [
'algorithm' => 'sodium',
'time_cost' => 8,
'memory_cost' => 128 * 1024,
],
],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

<encoder class="JMS\FooBundle\Entity\User6" algorithm="bcrypt" cost="15" />

<encoder class="JMS\FooBundle\Entity\User7" algorithm="native" time-cost="8" memory-cost="100" cost="15" />

<encoder class="JMS\FooBundle\Entity\User8" algorithm="auto" />

<provider name="default">
<memory>
<user name="foo" password="foo" roles="ROLE_USER" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</imports>

<sec:config>
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="sodium" />
<sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="sodium" time-cost="8" memory-cost="131072" />
</sec:config>

</container>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ security:
JMS\FooBundle\Entity\User6:
algorithm: bcrypt
cost: 15
JMS\FooBundle\Entity\User7:
algorithm: native
time_cost: 8
memory_cost: 100
cost: 15
JMS\FooBundle\Entity\User8:
algorithm: auto

providers:
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ security:
encoders:
JMS\FooBundle\Entity\User7:
algorithm: sodium
time_cost: 8
memory_cost: 131072
5 changes: 3 additions & 2 deletions src/Symfony/Component/Security/CHANGELOG.md
2851
Original file line numberDiff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ CHANGELOG
4.3.0
-----

* Added methods `__serialize` and `__unserialize` to the `TokenInterface`
* Added `SodiumPasswordEncoder` and `NativePasswordEncoder`
* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles
instead.
* The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0.
Expand All @@ -19,8 +21,7 @@ CHANGELOG
* Dispatch `AuthenticationFailureEvent` on `security.authentication.failure`
* Dispatch `InteractiveLoginEvent` on `security.interactive_login`
* Dispatch `SwitchUserEvent` on `security.switch_user`
* deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` instead
* Added methods `__serialize` and `__unserialize` to the `TokenInterface`
* Deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder`

4.2.0
-----
Expand Down
19 changes: 18 additions & 1 deletion src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ private function createEncoder(array $config)

private function getEncoderConfigFromAlgorithm($config)
{
if ('auto' === $config['algorithm']) {
$config['algorithm'] = SodiumPasswordEncoder::isSupported() ? 'sodium' : 'native';
}

switch ($config['algorithm']) {
case 'plaintext':
return [
Expand All @@ -108,10 +112,23 @@ private function getEncoderConfigFromAlgorithm($config)
'arguments' => [$config['cost']],
];

case 'native':
return [
'class' => NativePasswordEncoder::class,
'arguments' => [
$config['time_cost'] ?? null,
(($config['memory_cost'] ?? 0) << 10) ?: null,
$config['cost'] ?? null,
],
];

case 'sodium':
return [
'class' => SodiumPasswordEncoder::class,
'arguments' => [],
'arguments' => [
$config['time_cost'] ?? null,
(($config['memory_cost'] ?? 0) << 10) ?: null,
],
];

/* @deprecated since Symfony 4.3 */
Expand Down
Loading
0