first commit
This commit is contained in:
13
plugins/simplesaml/lib/vendor/symfony/password-hasher/CHANGELOG.md
vendored
Normal file
13
plugins/simplesaml/lib/vendor/symfony/password-hasher/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Use `SensitiveParameter` attribute to redact sensitive values in back traces
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* Add the component
|
||||
* Use `bcrypt` as default algorithm in `NativePasswordHasher`
|
215
plugins/simplesaml/lib/vendor/symfony/password-hasher/Command/UserPasswordHashCommand.php
vendored
Normal file
215
plugins/simplesaml/lib/vendor/symfony/password-hasher/Command/UserPasswordHashCommand.php
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
<?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\PasswordHasher\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes a user's password.
|
||||
*
|
||||
* @author Sarah Khalil <mkhalil.sarah@gmail.com>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'security:hash-password', description: 'Hash a user password')]
|
||||
class UserPasswordHashCommand extends Command
|
||||
{
|
||||
private PasswordHasherFactoryInterface $hasherFactory;
|
||||
private array $userClasses;
|
||||
|
||||
public function __construct(PasswordHasherFactoryInterface $hasherFactory, array $userClasses = [])
|
||||
{
|
||||
$this->hasherFactory = $hasherFactory;
|
||||
$this->userClasses = $userClasses;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('password', InputArgument::OPTIONAL, 'The plain password to hash.')
|
||||
->addArgument('user-class', InputArgument::OPTIONAL, 'The User entity class path associated with the hasher used to hash the password.')
|
||||
->addOption('empty-salt', null, InputOption::VALUE_NONE, 'Do not generate a salt or let the hasher generate one.')
|
||||
->setHelp(<<<EOF
|
||||
|
||||
The <info>%command.name%</info> command hashes passwords according to your
|
||||
security configuration. This command is mainly used to generate passwords for
|
||||
the <comment>in_memory</comment> user provider type and for changing passwords
|
||||
in the database while developing the application.
|
||||
|
||||
Suppose that you have the following security configuration in your application:
|
||||
|
||||
<comment>
|
||||
# config/packages/security.yml
|
||||
security:
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\InMemoryUser: plaintext
|
||||
App\Entity\User: auto
|
||||
</comment>
|
||||
|
||||
If you execute the command non-interactively, the first available configured
|
||||
user class under the <comment>security.password_hashers</comment> key is used and a random salt is
|
||||
generated to hash the password:
|
||||
|
||||
<info>php %command.full_name% --no-interaction [password]</info>
|
||||
|
||||
Pass the full user class path as the second argument to hash passwords for
|
||||
your own entities:
|
||||
|
||||
<info>php %command.full_name% --no-interaction [password] 'App\Entity\User'</info>
|
||||
|
||||
Executing the command interactively allows you to generate a random salt for
|
||||
hashing the password:
|
||||
|
||||
<info>php %command.full_name% [password] 'App\Entity\User'</info>
|
||||
|
||||
In case your hasher doesn't require a salt, add the <comment>empty-salt</comment> option:
|
||||
|
||||
<info>php %command.full_name% --empty-salt [password] 'App\Entity\User'</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $output instanceof ConsoleOutputInterface ? new SymfonyStyle($input, $output->getErrorOutput()) : $io;
|
||||
|
||||
$input->isInteractive() ? $errorIo->title('Symfony Password Hash Utility') : $errorIo->newLine();
|
||||
|
||||
$password = $input->getArgument('password');
|
||||
$userClass = $this->getUserClass($input, $io);
|
||||
$emptySalt = $input->getOption('empty-salt');
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($userClass);
|
||||
$saltlessWithoutEmptySalt = !$emptySalt && !$hasher instanceof LegacyPasswordHasherInterface;
|
||||
|
||||
if ($saltlessWithoutEmptySalt) {
|
||||
$emptySalt = true;
|
||||
}
|
||||
|
||||
if (!$password) {
|
||||
if (!$input->isInteractive()) {
|
||||
$errorIo->error('The password must not be empty.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
$passwordQuestion = $this->createPasswordQuestion();
|
||||
$password = $errorIo->askQuestion($passwordQuestion);
|
||||
}
|
||||
|
||||
$salt = null;
|
||||
|
||||
if ($input->isInteractive() && !$emptySalt) {
|
||||
$emptySalt = true;
|
||||
|
||||
$errorIo->note('The command will take care of generating a salt for you. Be aware that some hashers advise to let them generate their own salt. If you\'re using one of those hashers, please answer \'no\' to the question below. '.\PHP_EOL.'Provide the \'empty-salt\' option in order to let the hasher handle the generation itself.');
|
||||
|
||||
if ($errorIo->confirm('Confirm salt generation ?')) {
|
||||
$salt = $this->generateSalt();
|
||||
$emptySalt = false;
|
||||
}
|
||||
} elseif (!$emptySalt) {
|
||||
$salt = $this->generateSalt();
|
||||
}
|
||||
|
||||
$hashedPassword = $hasher->hash($password, $salt);
|
||||
|
||||
$rows = [
|
||||
['Hasher used', $hasher::class],
|
||||
['Password hash', $hashedPassword],
|
||||
];
|
||||
if (!$emptySalt) {
|
||||
$rows[] = ['Generated salt', $salt];
|
||||
}
|
||||
$io->table(['Key', 'Value'], $rows);
|
||||
|
||||
if (!$emptySalt) {
|
||||
$errorIo->note(sprintf('Make sure that your salt storage field fits the salt length: %s chars', \strlen($salt)));
|
||||
} elseif ($saltlessWithoutEmptySalt) {
|
||||
$errorIo->note('Self-salting hasher used: the hasher generated its own built-in salt.');
|
||||
}
|
||||
|
||||
$errorIo->success('Password hashing succeeded');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('user-class')) {
|
||||
$suggestions->suggestValues($this->userClasses);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the password question to ask the user for the password to be hashed.
|
||||
*/
|
||||
private function createPasswordQuestion(): Question
|
||||
{
|
||||
$passwordQuestion = new Question('Type in your password to be hashed');
|
||||
|
||||
return $passwordQuestion->setValidator(function ($value) {
|
||||
if ('' === trim($value)) {
|
||||
throw new InvalidArgumentException('The password must not be empty.');
|
||||
}
|
||||
|
||||
return $value;
|
||||
})->setHidden(true)->setMaxAttempts(20);
|
||||
}
|
||||
|
||||
private function generateSalt(): string
|
||||
{
|
||||
return base64_encode(random_bytes(30));
|
||||
}
|
||||
|
||||
private function getUserClass(InputInterface $input, SymfonyStyle $io): string
|
||||
{
|
||||
if (null !== $userClass = $input->getArgument('user-class')) {
|
||||
return $userClass;
|
||||
}
|
||||
|
||||
if (!$this->userClasses) {
|
||||
throw new RuntimeException('There are no configured password hashers for the "security" extension.');
|
||||
}
|
||||
|
||||
if (!$input->isInteractive() || 1 === \count($this->userClasses)) {
|
||||
return reset($this->userClasses);
|
||||
}
|
||||
|
||||
$userClasses = $this->userClasses;
|
||||
natcasesort($userClasses);
|
||||
$userClasses = array_values($userClasses);
|
||||
|
||||
return $io->choice('For which user class would you like to hash a password?', $userClasses, reset($userClasses));
|
||||
}
|
||||
}
|
21
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/ExceptionInterface.php
vendored
Normal file
21
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/ExceptionInterface.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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\PasswordHasher\Exception;
|
||||
|
||||
/**
|
||||
* Interface for exceptions thrown by the password-hasher component.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
interface ExceptionInterface extends \Throwable
|
||||
{
|
||||
}
|
23
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/InvalidPasswordException.php
vendored
Normal file
23
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/InvalidPasswordException.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\PasswordHasher\Exception;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
class InvalidPasswordException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
public function __construct(string $message = 'Invalid password.', int $code = 0, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
19
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/LogicException.php
vendored
Normal file
19
plugins/simplesaml/lib/vendor/symfony/password-hasher/Exception/LogicException.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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\PasswordHasher\Exception;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
class LogicException extends \LogicException implements ExceptionInterface
|
||||
{
|
||||
}
|
25
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/CheckPasswordLengthTrait.php
vendored
Normal file
25
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/CheckPasswordLengthTrait.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
trait CheckPasswordLengthTrait
|
||||
{
|
||||
private function isPasswordTooLong(#[\SensitiveParameter] string $password): bool
|
||||
{
|
||||
return PasswordHasherInterface::MAX_PASSWORD_LENGTH < \strlen($password);
|
||||
}
|
||||
}
|
98
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/MessageDigestPasswordHasher.php
vendored
Normal file
98
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/MessageDigestPasswordHasher.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* MessageDigestPasswordHasher uses a message digest algorithm.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MessageDigestPasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private string $algorithm;
|
||||
private bool $encodeHashAsBase64;
|
||||
private int $iterations = 1;
|
||||
private int $hashLength = -1;
|
||||
|
||||
/**
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
*/
|
||||
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 5000)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
|
||||
try {
|
||||
$this->hashLength = \strlen($this->hash('', 'salt'));
|
||||
} catch (\LogicException) {
|
||||
// ignore algorithm not supported
|
||||
}
|
||||
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword, ?string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (!\in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$salted = $this->mergePasswordAndSalt($plainPassword, $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);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword, ?string $salt = null): bool
|
||||
{
|
||||
if (\strlen($hashedPassword) !== $this->hashLength || str_contains($hashedPassword, '$')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$this->isPasswordTooLong($plainPassword) && hash_equals($hashedPassword, $this->hash($plainPassword, $salt));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function mergePasswordAndSalt(#[\SensitiveParameter] string $password, ?string $salt): string
|
||||
{
|
||||
if (!$salt) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
|
||||
throw new \InvalidArgumentException('Cannot use { or } in salt.');
|
||||
}
|
||||
|
||||
return $password.'{'.$salt.'}';
|
||||
}
|
||||
}
|
64
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/MigratingPasswordHasher.php
vendored
Normal file
64
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/MigratingPasswordHasher.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using the best available hasher.
|
||||
* Verifies them using a chain of hashers.
|
||||
*
|
||||
* /!\ Don't put a PlaintextPasswordHasher in the list as that'd mean a leaked hash
|
||||
* could be used to authenticate successfully without knowing the cleartext password.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class MigratingPasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
private PasswordHasherInterface $bestHasher;
|
||||
private array $extraHashers;
|
||||
|
||||
public function __construct(PasswordHasherInterface $bestHasher, PasswordHasherInterface ...$extraHashers)
|
||||
{
|
||||
$this->bestHasher = $bestHasher;
|
||||
$this->extraHashers = $extraHashers;
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword, ?string $salt = null): string
|
||||
{
|
||||
return $this->bestHasher->hash($plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword, ?string $salt = null): bool
|
||||
{
|
||||
if ($this->bestHasher->verify($hashedPassword, $plainPassword, $salt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->bestHasher->needsRehash($hashedPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->extraHashers as $hasher) {
|
||||
if ($hasher->verify($hashedPassword, $plainPassword, $salt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return $this->bestHasher->needsRehash($hashedPassword);
|
||||
}
|
||||
}
|
117
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/NativePasswordHasher.php
vendored
Normal file
117
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/NativePasswordHasher.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using password_hash().
|
||||
*
|
||||
* @author Elnur Abdurrakhimov <elnur@elnur.pro>
|
||||
* @author Terje Bråten <terje@braten.be>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class NativePasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private string $algorithm = \PASSWORD_BCRYPT;
|
||||
private array $options;
|
||||
|
||||
/**
|
||||
* @param string|null $algorithm An algorithm supported by password_hash() or null to use the best available algorithm
|
||||
*/
|
||||
public function __construct(?int $opsLimit = null, ?int $memLimit = null, ?int $cost = null, ?string $algorithm = null)
|
||||
{
|
||||
$cost ??= 13;
|
||||
$opsLimit ??= max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
||||
$memLimit ??= max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024);
|
||||
|
||||
if (3 > $opsLimit) {
|
||||
throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
|
||||
}
|
||||
|
||||
if (10 * 1024 > $memLimit) {
|
||||
throw new \InvalidArgumentException('$memLimit must be 10k or greater.');
|
||||
}
|
||||
|
||||
if ($cost < 4 || 31 < $cost) {
|
||||
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
|
||||
}
|
||||
|
||||
if (null !== $algorithm) {
|
||||
$algorithms = [1 => \PASSWORD_BCRYPT, '2y' => \PASSWORD_BCRYPT];
|
||||
|
||||
if (\defined('PASSWORD_ARGON2I')) {
|
||||
$algorithms[2] = $algorithms['argon2i'] = \PASSWORD_ARGON2I;
|
||||
}
|
||||
|
||||
if (\defined('PASSWORD_ARGON2ID')) {
|
||||
$algorithms[3] = $algorithms['argon2id'] = \PASSWORD_ARGON2ID;
|
||||
}
|
||||
|
||||
$this->algorithm = $algorithms[$algorithm] ?? $algorithm;
|
||||
}
|
||||
|
||||
$this->options = [
|
||||
'cost' => $cost,
|
||||
'time_cost' => $opsLimit,
|
||||
'memory_cost' => $memLimit >> 10,
|
||||
'threads' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (\PASSWORD_BCRYPT === $this->algorithm && (72 < \strlen($plainPassword) || str_contains($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
return password_hash($plainPassword, $this->algorithm, $this->options);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword): bool
|
||||
{
|
||||
if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!str_starts_with($hashedPassword, '$argon')) {
|
||||
// Bcrypt cuts on NUL chars and after 72 bytes
|
||||
if (str_starts_with($hashedPassword, '$2') && (72 < \strlen($plainPassword) || str_contains($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('sodium') && version_compare(\SODIUM_LIBRARY_VERSION, '1.0.14', '>=')) {
|
||||
return sodium_crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium') && version_compare(phpversion('libsodium'), '1.0.14', '>=')) {
|
||||
return \Sodium\crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return password_needs_rehash($hashedPassword, $this->algorithm, $this->options);
|
||||
}
|
||||
}
|
26
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherAwareInterface.php
vendored
Normal file
26
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherAwareInterface.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
/**
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
interface PasswordHasherAwareInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the password hasher used to hash the password.
|
||||
*
|
||||
* If the method returns null, the standard way to retrieve the password hasher
|
||||
* will be used instead.
|
||||
*/
|
||||
public function getPasswordHasherName(): ?string;
|
||||
}
|
240
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherFactory.php
vendored
Normal file
240
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherFactory.php
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* A generic hasher factory implementation.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
class PasswordHasherFactory implements PasswordHasherFactoryInterface
|
||||
{
|
||||
private array $passwordHashers;
|
||||
|
||||
/**
|
||||
* @param array<string, PasswordHasherInterface|array> $passwordHashers
|
||||
*/
|
||||
public function __construct(array $passwordHashers)
|
||||
{
|
||||
$this->passwordHashers = $passwordHashers;
|
||||
}
|
||||
|
||||
public function getPasswordHasher(string|PasswordAuthenticatedUserInterface|PasswordHasherAwareInterface $user): PasswordHasherInterface
|
||||
{
|
||||
$hasherKey = null;
|
||||
|
||||
if ($user instanceof PasswordHasherAwareInterface && null !== $hasherName = $user->getPasswordHasherName()) {
|
||||
if (!\array_key_exists($hasherName, $this->passwordHashers)) {
|
||||
throw new \RuntimeException(sprintf('The password hasher "%s" was not configured.', $hasherName));
|
||||
}
|
||||
|
||||
$hasherKey = $hasherName;
|
||||
} else {
|
||||
foreach ($this->passwordHashers as $class => $hasher) {
|
||||
if ((\is_object($user) && $user instanceof $class) || (!\is_object($user) && (is_subclass_of($user, $class) || $user == $class))) {
|
||||
$hasherKey = $class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $hasherKey) {
|
||||
throw new \RuntimeException(sprintf('No password hasher has been configured for account "%s".', \is_object($user) ? get_debug_type($user) : $user));
|
||||
}
|
||||
|
||||
if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) {
|
||||
$this->passwordHashers[$hasherKey] = $this->createHasher($this->passwordHashers[$hasherKey]);
|
||||
}
|
||||
|
||||
return $this->passwordHashers[$hasherKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the actual hasher instance.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function createHasher(array $config, bool $isExtra = false): PasswordHasherInterface
|
||||
{
|
||||
if (isset($config['instance'])) {
|
||||
if (!isset($config['migrate_from'])) {
|
||||
return $config['instance'];
|
||||
}
|
||||
|
||||
$config = $this->getMigratingPasswordConfig($config);
|
||||
}
|
||||
|
||||
if (isset($config['algorithm'])) {
|
||||
$rawConfig = $config;
|
||||
$config = $this->getHasherConfigFromAlgorithm($config);
|
||||
}
|
||||
if (!isset($config['class'])) {
|
||||
throw new \InvalidArgumentException('"class" must be set in '.json_encode($config));
|
||||
}
|
||||
if (!isset($config['arguments'])) {
|
||||
throw new \InvalidArgumentException('"arguments" must be set in '.json_encode($config));
|
||||
}
|
||||
|
||||
$hasher = new $config['class'](...$config['arguments']);
|
||||
|
||||
if ($isExtra || !\in_array($config['class'], [NativePasswordHasher::class, SodiumPasswordHasher::class], true)) {
|
||||
return $hasher;
|
||||
}
|
||||
|
||||
if ($rawConfig ?? null) {
|
||||
$extrapasswordHashers = array_map(function (string $algo) use ($rawConfig): PasswordHasherInterface {
|
||||
$rawConfig['algorithm'] = $algo;
|
||||
|
||||
return $this->createHasher($rawConfig);
|
||||
}, ['pbkdf2', $rawConfig['hash_algorithm'] ?? 'sha512']);
|
||||
} else {
|
||||
$extrapasswordHashers = [new Pbkdf2PasswordHasher(), new MessageDigestPasswordHasher()];
|
||||
}
|
||||
|
||||
return new MigratingPasswordHasher($hasher, ...$extrapasswordHashers);
|
||||
}
|
||||
|
||||
private function getHasherConfigFromAlgorithm(array $config): array
|
||||
{
|
||||
if ('auto' === $config['algorithm']) {
|
||||
// "plaintext" is not listed as any leaked hashes could then be used to authenticate directly
|
||||
if (SodiumPasswordHasher::isSupported()) {
|
||||
$algorithms = ['native', 'sodium', 'pbkdf2'];
|
||||
} else {
|
||||
$algorithms = ['native', 'pbkdf2'];
|
||||
}
|
||||
|
||||
if ($config['hash_algorithm'] ?? '') {
|
||||
$algorithms[] = $config['hash_algorithm'];
|
||||
}
|
||||
|
||||
$hasherChain = [];
|
||||
foreach ($algorithms as $algorithm) {
|
||||
$config['algorithm'] = $algorithm;
|
||||
$hasherChain[] = $this->createHasher($config, true);
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MigratingPasswordHasher::class,
|
||||
'arguments' => $hasherChain,
|
||||
];
|
||||
}
|
||||
|
||||
if ($config['migrate_from'] ?? false) {
|
||||
return $this->getMigratingPasswordConfig($config);
|
||||
}
|
||||
|
||||
switch ($config['algorithm']) {
|
||||
case 'plaintext':
|
||||
return [
|
||||
'class' => PlaintextPasswordHasher::class,
|
||||
'arguments' => [$config['ignore_case'] ?? false],
|
||||
];
|
||||
|
||||
case 'pbkdf2':
|
||||
return [
|
||||
'class' => Pbkdf2PasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['hash_algorithm'] ?? 'sha512',
|
||||
$config['encode_as_base64'] ?? true,
|
||||
$config['iterations'] ?? 1000,
|
||||
$config['key_length'] ?? 40,
|
||||
],
|
||||
];
|
||||
|
||||
case 'bcrypt':
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_BCRYPT;
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
|
||||
case 'native':
|
||||
return [
|
||||
'class' => NativePasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'] ?? null,
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
$config['cost'] ?? null,
|
||||
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||
];
|
||||
|
||||
case 'sodium':
|
||||
return [
|
||||
'class' => SodiumPasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'] ?? null,
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
],
|
||||
];
|
||||
|
||||
case 'argon2i':
|
||||
if (SodiumPasswordHasher::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2I;
|
||||
} else {
|
||||
throw new LogicException(sprintf('Algorithm "argon2i" is not available. Use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id" or "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
|
||||
case 'argon2id':
|
||||
if (($hasSodium = SodiumPasswordHasher::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2ID;
|
||||
} else {
|
||||
throw new LogicException(sprintf('Algorithm "argon2id" is not available. Either use "%s", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MessageDigestPasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['algorithm'],
|
||||
$config['encode_as_base64'] ?? true,
|
||||
$config['iterations'] ?? 5000,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function getMigratingPasswordConfig(array $config): array
|
||||
{
|
||||
$frompasswordHashers = $config['migrate_from'];
|
||||
unset($config['migrate_from']);
|
||||
$hasherChain = [$this->createHasher($config, true)];
|
||||
|
||||
foreach ($frompasswordHashers as $name) {
|
||||
if ($hasher = $this->passwordHashers[$name] ?? false) {
|
||||
$hasher = $hasher instanceof PasswordHasherInterface ? $hasher : $this->createHasher($hasher, true);
|
||||
} else {
|
||||
$hasher = $this->createHasher(['algorithm' => $name], true);
|
||||
}
|
||||
|
||||
$hasherChain[] = $hasher;
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MigratingPasswordHasher::class,
|
||||
'arguments' => $hasherChain,
|
||||
];
|
||||
}
|
||||
}
|
31
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherFactoryInterface.php
vendored
Normal file
31
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PasswordHasherFactoryInterface.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* PasswordHasherFactoryInterface to support different password hashers for different user accounts.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface PasswordHasherFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Returns the password hasher to use for the given user.
|
||||
*
|
||||
* @throws \RuntimeException When no password hasher could be found for the user
|
||||
*/
|
||||
public function getPasswordHasher(string|PasswordAuthenticatedUserInterface|PasswordHasherAwareInterface $user): PasswordHasherInterface;
|
||||
}
|
90
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/Pbkdf2PasswordHasher.php
vendored
Normal file
90
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/Pbkdf2PasswordHasher.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Pbkdf2PasswordHasher uses the PBKDF2 (Password-Based Key Derivation Function 2).
|
||||
*
|
||||
* Providing a high level of Cryptographic security,
|
||||
* PBKDF2 is recommended by the National Institute of Standards and Technology (NIST).
|
||||
*
|
||||
* But also warrants a warning, using PBKDF2 (with a high number of iterations) slows down the process.
|
||||
* PBKDF2 should be used with caution and care.
|
||||
*
|
||||
* @author Sebastiaan Stok <s.stok@rollerscapes.net>
|
||||
* @author Andrew Johnson
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
final class Pbkdf2PasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private string $algorithm;
|
||||
private bool $encodeHashAsBase64;
|
||||
private int $iterations = 1;
|
||||
private int $length;
|
||||
private int $encodedLength = -1;
|
||||
|
||||
/**
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
* @param int $length Length of derived key to create
|
||||
*/
|
||||
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 1000, int $length = 40)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
$this->length = $length;
|
||||
|
||||
try {
|
||||
$this->encodedLength = \strlen($this->hash('', 'salt'));
|
||||
} catch (\LogicException) {
|
||||
// ignore unsupported algorithm
|
||||
}
|
||||
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword, ?string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (!\in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$digest = hash_pbkdf2($this->algorithm, $plainPassword, $salt ?? '', $this->iterations, $this->length, true);
|
||||
|
||||
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword, ?string $salt = null): bool
|
||||
{
|
||||
if (\strlen($hashedPassword) !== $this->encodedLength || str_contains($hashedPassword, '$')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$this->isPasswordTooLong($plainPassword) && hash_equals($hashedPassword, $this->hash($plainPassword, $salt));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
79
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PlaintextPasswordHasher.php
vendored
Normal file
79
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/PlaintextPasswordHasher.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* PlaintextPasswordHasher does not do any hashing but is useful in testing environments.
|
||||
*
|
||||
* As this hasher is not cryptographically secure, usage of it in production environments is discouraged.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PlaintextPasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private bool $ignorePasswordCase;
|
||||
|
||||
/**
|
||||
* @param bool $ignorePasswordCase Compare password case-insensitive
|
||||
*/
|
||||
public function __construct(bool $ignorePasswordCase = false)
|
||||
{
|
||||
$this->ignorePasswordCase = $ignorePasswordCase;
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword, ?string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
return $this->mergePasswordAndSalt($plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword, ?string $salt = null): bool
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pass2 = $this->mergePasswordAndSalt($plainPassword, $salt);
|
||||
|
||||
if (!$this->ignorePasswordCase) {
|
||||
return hash_equals($hashedPassword, $pass2);
|
||||
}
|
||||
|
||||
return hash_equals(strtolower($hashedPassword), strtolower($pass2));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function mergePasswordAndSalt(#[\SensitiveParameter] string $password, ?string $salt): string
|
||||
{
|
||||
if (empty($salt)) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
|
||||
throw new \InvalidArgumentException('Cannot use { or } in salt.');
|
||||
}
|
||||
|
||||
return $password.'{'.$salt.'}';
|
||||
}
|
||||
}
|
114
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/SodiumPasswordHasher.php
vendored
Normal file
114
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/SodiumPasswordHasher.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using libsodium.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Zan Baldwin <hello@zanbaldwin.com>
|
||||
* @author Dominik Müller <dominik.mueller@jkweb.ch>
|
||||
*/
|
||||
final class SodiumPasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private int $opsLimit;
|
||||
private int $memLimit;
|
||||
|
||||
public function __construct(?int $opsLimit = null, ?int $memLimit = null)
|
||||
{
|
||||
if (!self::isSupported()) {
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
|
||||
$this->opsLimit = $opsLimit ?? max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
||||
$this->memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024);
|
||||
|
||||
if (3 > $this->opsLimit) {
|
||||
throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
|
||||
}
|
||||
|
||||
if (10 * 1024 > $this->memLimit) {
|
||||
throw new \InvalidArgumentException('$memLimit must be 10k or greater.');
|
||||
}
|
||||
}
|
||||
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return version_compare(\extension_loaded('sodium') ? \SODIUM_LIBRARY_VERSION : phpversion('libsodium'), '1.0.14', '>=');
|
||||
}
|
||||
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (\function_exists('sodium_crypto_pwhash_str')) {
|
||||
return sodium_crypto_pwhash_str($plainPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str($plainPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword): bool
|
||||
{
|
||||
if ('' === $plainPassword) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!str_starts_with($hashedPassword, '$argon')) {
|
||||
if (str_starts_with($hashedPassword, '$2') && (72 < \strlen($plainPassword) || str_contains($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
// Accept validating non-argon passwords for seamless migrations
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
if (\function_exists('sodium_crypto_pwhash_str_verify')) {
|
||||
return sodium_crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
if (\function_exists('sodium_crypto_pwhash_str_needs_rehash')) {
|
||||
return sodium_crypto_pwhash_str_needs_rehash($hashedPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str_needs_rehash($hashedPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
}
|
71
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/UserPasswordHasher.php
vendored
Normal file
71
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/UserPasswordHasher.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords based on the user and the PasswordHasherFactory.
|
||||
*
|
||||
* @author Ariel Ferrandini <arielferrandini@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class UserPasswordHasher implements UserPasswordHasherInterface
|
||||
{
|
||||
private PasswordHasherFactoryInterface $hasherFactory;
|
||||
|
||||
public function __construct(PasswordHasherFactoryInterface $hasherFactory)
|
||||
{
|
||||
$this->hasherFactory = $hasherFactory;
|
||||
}
|
||||
|
||||
public function hashPassword(PasswordAuthenticatedUserInterface $user, #[\SensitiveParameter] string $plainPassword): string
|
||||
{
|
||||
$salt = null;
|
||||
if ($user instanceof LegacyPasswordAuthenticatedUserInterface) {
|
||||
$salt = $user->getSalt();
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->hash($plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function isPasswordValid(PasswordAuthenticatedUserInterface $user, #[\SensitiveParameter] string $plainPassword): bool
|
||||
{
|
||||
$salt = null;
|
||||
if ($user instanceof LegacyPasswordAuthenticatedUserInterface) {
|
||||
$salt = $user->getSalt();
|
||||
}
|
||||
|
||||
if (null === $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->verify($user->getPassword(), $plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function needsRehash(PasswordAuthenticatedUserInterface $user): bool
|
||||
{
|
||||
if (null === $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->needsRehash($user->getPassword());
|
||||
}
|
||||
}
|
37
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/UserPasswordHasherInterface.php
vendored
Normal file
37
plugins/simplesaml/lib/vendor/symfony/password-hasher/Hasher/UserPasswordHasherInterface.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* Interface for the user password hasher service.
|
||||
*
|
||||
* @author Ariel Ferrandini <arielferrandini@gmail.com>
|
||||
*/
|
||||
interface UserPasswordHasherInterface
|
||||
{
|
||||
/**
|
||||
* Hashes the plain password for the given user.
|
||||
*/
|
||||
public function hashPassword(PasswordAuthenticatedUserInterface $user, #[\SensitiveParameter] string $plainPassword): string;
|
||||
|
||||
/**
|
||||
* Checks if the plaintext password matches the user's password.
|
||||
*/
|
||||
public function isPasswordValid(PasswordAuthenticatedUserInterface $user, #[\SensitiveParameter] string $plainPassword): bool;
|
||||
|
||||
/**
|
||||
* Checks if an encoded password would benefit from rehashing.
|
||||
*/
|
||||
public function needsRehash(PasswordAuthenticatedUserInterface $user): bool;
|
||||
}
|
19
plugins/simplesaml/lib/vendor/symfony/password-hasher/LICENSE
vendored
Normal file
19
plugins/simplesaml/lib/vendor/symfony/password-hasher/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
36
plugins/simplesaml/lib/vendor/symfony/password-hasher/LegacyPasswordHasherInterface.php
vendored
Normal file
36
plugins/simplesaml/lib/vendor/symfony/password-hasher/LegacyPasswordHasherInterface.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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\PasswordHasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
|
||||
/**
|
||||
* Provides password hashing and verification capabilities for "legacy" hashers that require external salts.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
interface LegacyPasswordHasherInterface extends PasswordHasherInterface
|
||||
{
|
||||
/**
|
||||
* Hashes a plain password.
|
||||
*
|
||||
* @throws InvalidPasswordException If the plain password is invalid, e.g. excessively long
|
||||
*/
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword, ?string $salt = null): string;
|
||||
|
||||
/**
|
||||
* Checks that a plain password and a salt match a password hash.
|
||||
*/
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword, ?string $salt = null): bool;
|
||||
}
|
43
plugins/simplesaml/lib/vendor/symfony/password-hasher/PasswordHasherInterface.php
vendored
Normal file
43
plugins/simplesaml/lib/vendor/symfony/password-hasher/PasswordHasherInterface.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\PasswordHasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
|
||||
/**
|
||||
* Provides password hashing capabilities.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
interface PasswordHasherInterface
|
||||
{
|
||||
public const MAX_PASSWORD_LENGTH = 4096;
|
||||
|
||||
/**
|
||||
* Hashes a plain password.
|
||||
*
|
||||
* @throws InvalidPasswordException When the plain password is invalid, e.g. excessively long
|
||||
*/
|
||||
public function hash(#[\SensitiveParameter] string $plainPassword): string;
|
||||
|
||||
/**
|
||||
* Verifies a plain password against a hash.
|
||||
*/
|
||||
public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword): bool;
|
||||
|
||||
/**
|
||||
* Checks if a password hash would benefit from rehashing.
|
||||
*/
|
||||
public function needsRehash(string $hashedPassword): bool;
|
||||
}
|
40
plugins/simplesaml/lib/vendor/symfony/password-hasher/README.md
vendored
Normal file
40
plugins/simplesaml/lib/vendor/symfony/password-hasher/README.md
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
PasswordHasher Component
|
||||
========================
|
||||
|
||||
The PasswordHasher component provides secure password hashing utilities.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
```
|
||||
$ composer require symfony/password-hasher
|
||||
```
|
||||
|
||||
```php
|
||||
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory;
|
||||
|
||||
// Configure different password hashers via the factory
|
||||
$factory = new PasswordHasherFactory([
|
||||
'common' => ['algorithm' => 'bcrypt'],
|
||||
'memory-hard' => ['algorithm' => 'sodium'],
|
||||
]);
|
||||
|
||||
// Retrieve the right password hasher by its name
|
||||
$passwordHasher = $factory->getPasswordHasher('common');
|
||||
|
||||
// Hash a plain password
|
||||
$hash = $passwordHasher->hash('plain'); // returns a bcrypt hash
|
||||
|
||||
// Verify that a given plain password matches the hash
|
||||
$passwordHasher->verify($hash, 'wrong'); // returns false
|
||||
$passwordHasher->verify($hash, 'plain'); // returns true (valid)
|
||||
```
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/security.html#c-hashing-passwords)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
35
plugins/simplesaml/lib/vendor/symfony/password-hasher/composer.json
vendored
Normal file
35
plugins/simplesaml/lib/vendor/symfony/password-hasher/composer.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "symfony/password-hasher",
|
||||
"type": "library",
|
||||
"description": "Provides password hashing utilities",
|
||||
"keywords": ["password", "hashing"],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Robin Chalas",
|
||||
"email": "robin.chalas@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/security-core": "^5.4|^6.0|^7.0",
|
||||
"symfony/console": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/security-core": "<5.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\PasswordHasher\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
Reference in New Issue
Block a user