8000 [Security] Restore extension point in MessageDigestPasswordEncoder by derrabus · Pull Request #41703 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Security] Restore extension point in MessageDigestPasswordEncoder #41703

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
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
[Security] Restore extension point in MessageDigestPasswordEncoder
Signed-off-by: Alexander M. Turek <me@derrabus.de>
  • Loading branch information
derrabus committed Jun 15, 2021
commit 4568876d0cbf7921f8317193c66d6a6d16d29ea8
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Core\Encoder;

use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;

trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', MessageDigestPasswordEncoder::class, MessageDigestPasswordHasher::class);

Expand All @@ -24,7 +25,10 @@
*/
class MessageDigestPasswordEncoder extends BasePasswordEncoder
{
use LegacyEncoderTrait;
private $algorithm;
private $encodeHashAsBase64;
private $iterations = 1;
private $encodedLength = -1;

/**
* @param string $algorithm The digest algorithm to use
Expand All @@ -33,6 +37,51 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
*/
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 5000)
{
$this->hasher = new MessageDigestPasswordHasher($algorithm, $encodeHashAsBase64, $iterations);
$this->algorithm = $algorithm;
$this->encodeHashAsBase64 = $encodeHashAsBase64;

try {
$this->encodedLength = \strlen($this->encodePassword('', 'salt'));
} catch (\LogicException $e) {
// ignore algorithm not supported
}

$this->iterations = $iterations;
}

/**
* {@inheritdoc}
*/
public function encodePassword(string $raw, ?string $salt)
{
if ($this->isPasswordTooLong($raw)) {
throw new BadCredentialsException('Invalid password.');
}

if (!\in_array($this->algorithm, hash_algos(), true)) {
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
}

$salted = $this->mergePasswordAndSalt($raw, $salt);
$digest = hash($this->algorithm, $salted, true);

// "stretch" hash
for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}

return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
}

/**
* {@inheritdoc}
*/
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
{
if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) {
return false;
}

return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Security\Core\Tests\Encoder\Fixtures;

use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;

final class MyMessageDigestPasswordEncoder extends MessageDigestPasswordEncoder
{
public function __construct()
{
parent::__construct('sha512', true, 1);
}

protected function mergePasswordAndSalt(string $password, ?string $salt): string
{
return json_encode(['password' => $password, 'salt' => $salt]);
}

protected function demergePasswordAndSalt(string $mergedPasswordSalt): array
{
['password' => $password, 'salt' => $salt] = json_decode($mergedPasswordSalt, true);

return [$password, $salt];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Tests\Encoder\Fixtures\MyMessageDigestPasswordEncoder;

/**
* @group legacy
Expand Down Expand Up @@ -60,4 +61,13 @@ public function testCheckPasswordLength()

$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
}

public function testCustomEncoder()
{
$encoder = new MyMessageDigestPasswordEncoder();
$encodedPassword = $encoder->encodePassword('p4ssw0rd', 's417');

$this->assertSame(base64_encode(hash('sha512', '{"password":"p4ssw0rd","salt":"s417"}', true)), $encodedPassword);
$this->assertTrue($encoder->isPasswordValid($encodedPassword, 'p4ssw0rd', 's417'));
}
}
0