hydra-sql/src/Security/Hasher/PasswordEncoder.php

118 lines
3.7 KiB
PHP

<?php
namespace App\Security\Hasher;
use App\SQLLogin\Exception\InvalidSQLLoginConfigurationException;
use App\SQLLogin\Exception\InvalidSQLPasswordException;
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait;
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
class PasswordEncoder implements LegacyPasswordHasherInterface
{
use CheckPasswordLengthTrait;
public const PASSWORD_PATTERN = 'password';
public const SALT_PATTERN = 'salt';
public const PEPPER_PATTERN = 'pepper';
protected ?string $pepper;
protected array $hashAlgoLegacy;
protected array $securityPattern;
public function __construct(?string $pepper, string $hashAlgoLegacy, string $securityPattern)
{
$this->pepper = $pepper;
$this->hashAlgoLegacy = explode(',', $hashAlgoLegacy);
$this->securityPattern = explode(',', $securityPattern);
}
/**
* Pas utilisé, mais on doit le garder pour le implements
*/
public function hash(string $plainPassword, string $salt = null): string
{
if ($this->isPasswordTooLong($plainPassword)) {
throw new InvalidPasswordException();
}
return hash($plainPassword.$salt, $this->hashAlgoLegacy[0]);
}
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
{
if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) {
return false;
}
$completedPassword = $this->getPasswordToHash($plainPassword, $salt);
foreach ($this->hashAlgoLegacy as $algo) {
if ('ssha' === $algo && $this->compareSsha($hashedPassword, $completedPassword)) {
return true;
}
if ($this->isObsoleteAlgo($algo)) {
if (hash_equals(hash($algo, $completedPassword), $hashedPassword)) {
return true;
}
} else {
if (password_verify($completedPassword, $hashedPassword)) {
return true;
}
}
}
throw new InvalidSQLPasswordException();
}
public function needsRehash(string $hashedPassword): bool
{
return false;
}
public function isObsoleteAlgo($algo): bool
{
return in_array($algo, hash_algos());
}
/**
* Retourne la string à hasher en fonction du pattern indiqué
*
* @param mixed $plainTextPassword
* @param mixed $salt
*
* @return string
*/
protected function getPasswordToHash($plainTextPassword, $salt)
{
$arrayRef = [
self::PASSWORD_PATTERN => $plainTextPassword,
self::SALT_PATTERN => $salt,
self::PEPPER_PATTERN => $this->pepper,
];
foreach ($this->securityPattern as $term) {
if (self::PEPPER_PATTERN !== $term && self::PASSWORD_PATTERN !== $term && self::SALT_PATTERN !== $term) {
throw new InvalidSQLLoginConfigurationException();
}
}
$completedPlainPassword = '';
foreach ($this->securityPattern as $term) {
$completedPlainPassword .= $arrayRef[$term];
}
return $completedPlainPassword;
}
protected function compareSsha($hashPassword, $plainPassword)
{
$base_64_hash_with_salt = substr($hashPassword, 6);
$hash_with_salt = base64_decode($base_64_hash_with_salt);
$hash = substr($hash_with_salt, 0, 20);
$salt = substr($hash_with_salt, 20);
// hash given password
$hash_given = sha1($plainPassword.$salt, true);
return $hash == $hash_given;
}
}