ajout de l'updatde hashage selon algo indiqué en ver env, fix typo
Cadoles/hydra-sql/pipeline/pr-develop This commit is unstable Details

This commit is contained in:
Rudy Masson 2022-12-16 15:00:14 +01:00
parent 441c0f563c
commit bd1b035f1e
19 changed files with 247 additions and 57 deletions

5
.env
View File

@ -29,8 +29,9 @@ BASE_URL='http://localhost:8080'
# connexion hydra # connexion hydra
HYDRA_ADMIN_BASE_URL='http://hydra:4445' HYDRA_ADMIN_BASE_URL='http://hydra:4445'
APP_LOCALES="fr,en" APP_LOCALES="fr,en"
SECURITY_PATTERN=
NEW_HASH_ALGO=
HASH_ALGO_LEGACY="sha256"
###> symfony/lock ### ###> symfony/lock ###
# Choose one of the stores below # Choose one of the stores below
# postgresql+advisory://db_user:db_password@localhost/db_name # postgresql+advisory://db_user:db_password@localhost/db_name

8
.gitignore vendored
View File

@ -6,9 +6,7 @@
/config/secrets/prod/prod.decrypt.private.php /config/secrets/prod/prod.decrypt.private.php
/public/bundles/ /public/bundles/
/var/ /var/
###< symfony/framework-bundle ###
supervisord.log
supervisord.pid
/vendor /vendor
/tools/php-cs-fixer/vendor /tools/php-cs-fixer/vendor
###> symfony/webpack-encore-bundle ### ###> symfony/webpack-encore-bundle ###
@ -22,5 +20,5 @@ yarn-error.log
/.config /.config
/.npm /.npm
/.local /.local
supervisord.log /supervisord.log
supervisord.pid /supervisord.pid

View File

@ -10,7 +10,7 @@ security:
# algorithm: 'sha256' # algorithm: 'sha256'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers: providers:
pdo_user_provider: sql_login_provider:
id: App\Security\SQLLoginUserProvider id: App\Security\SQLLoginUserProvider
firewalls: firewalls:
dev: dev:
@ -19,7 +19,7 @@ security:
main: main:
# lazy: true # lazy: true
stateless: false stateless: false
provider: pdo_user_provider provider: sql_login_provider
custom_authenticators: custom_authenticators:
- App\Security\SQLLoginUserAuthenticator - App\Security\SQLLoginUserAuthenticator

View File

@ -9,8 +9,12 @@ parameters:
database.user: "%env(resolve:DB_USER)%" database.user: "%env(resolve:DB_USER)%"
database.password: "%env(resolve:DB_PASSWORD)%" database.password: "%env(resolve:DB_PASSWORD)%"
# algorythme de hahshage utilisé "md5", "sha256", "haval160,4", etc. # algorythme de hashage utilisé "md5", "sha256", "haval160,4", etc.
hashAlgo: "sha256" env(HASH_ALGO_LEGACY): "sha256"
hashAlgoLegacy: '%env(resolve:HASH_ALGO_LEGACY)%'
env(NEW_HASH_ALGO): "sha256"
newHashAlgo: '%env(resolve:NEW_HASH_ALGO)%'
# adresse du site hote # adresse du site hote
issuer_url: '%env(resolve:ISSUER_URL)%' issuer_url: '%env(resolve:ISSUER_URL)%'
@ -21,6 +25,7 @@ parameters:
default_locale: '%env(DEFAULT_LOCALE)%' default_locale: '%env(DEFAULT_LOCALE)%'
env(DEFAULT_LOCALE): 'fr' env(DEFAULT_LOCALE): 'fr'
security_pattern: '%env(resolve:SECURITY_PATTERN)%'
env(APP_LOCALES): "fr,en" env(APP_LOCALES): "fr,en"
locales: '%env(APP_LOCALES)%' locales: '%env(APP_LOCALES)%'
app.supported_locales: ~ app.supported_locales: ~
@ -65,6 +70,8 @@ services:
App\Security\Hasher\PasswordEncoder: App\Security\Hasher\PasswordEncoder:
arguments: arguments:
$pepper: '%pepper%' $pepper: '%pepper%'
$hashAlgo: '%hashAlgo%' $hashAlgoLegacy: '%hashAlgoLegacy%'
$newHashAlgo: '%newHashAlgo%'
$securityPattern: '%security_pattern%'
# add more service definitions when explicit configuration is needed # add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones # please note that last definitions always *replace* previous ones

View File

@ -10,6 +10,6 @@ INSERT INTO usager (email, password, salt, lastname, firstname) VALUES
('test3@test.com', '504ae1c3e2f5fdaf41f868164dabcef21e17059f5f388b452718a1ce92692c67', 'cesaltestunautreexemple', 'Dupont', 'Henri'); ('test3@test.com', '504ae1c3e2f5fdaf41f868164dabcef21e17059f5f388b452718a1ce92692c67', 'cesaltestunautreexemple', 'Dupont', 'Henri');
INSERT INTO usager (email, password, lastname, firstname) VALUES INSERT INTO usager (email, password, lastname, firstname) VALUES
('test4@test.com', '50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d', 'Durand', 'Isabelle'), ('test4@test.com', '$2a$12$zFN0VJ..Cuu.2itWQwmHJe5EUhNHazbMfCSJFpNiEfdwpLzjjDM0u', 'Durand', 'Isabelle'),
('test2@test.com', '50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d', 'Dubois', 'Angela'); ('test2@test.com', '50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d', 'Dubois', 'Angela');
GRANT ALL PRIVILEGES ON DATABASE usager TO lasql GRANT ALL PRIVILEGES ON DATABASE usager TO lasql

View File

@ -37,6 +37,9 @@ services:
- DB_PASSWORD=lasql - DB_PASSWORD=lasql
- DEFAULT_LOCALE=fr - DEFAULT_LOCALE=fr
- DSN_REMOTE_DATABASE=pgsql:host='postgres';port=5432;dbname=lasql; - DSN_REMOTE_DATABASE=pgsql:host='postgres';port=5432;dbname=lasql;
- HASH_ALGO_LEGACY=sha256
- NEW_HASH_ALGO=bcrypt
- SECURITY_PATTERN=password,salt,pepper
oidc-test: oidc-test:

View File

@ -34,6 +34,10 @@ BASE_URL='http://localhost:8080'
HYDRA_ADMIN_BASE_URL='http://hydra:4445' HYDRA_ADMIN_BASE_URL='http://hydra:4445'
DSN_REMOTE_DATABASE="pgsql:host='postgres';port=5432;dbname=lasql" DSN_REMOTE_DATABASE="pgsql:host='postgres';port=5432;dbname=lasql"
APP_LOCALES="fr,en" APP_LOCALES="fr,en"
NEW_HASH_ALGO="argon2id"
HASH_ALGO_LEGACY="sha256, bcrypt"
SECURITY_PATTERN="password,salt,pepper"
PEPPER
``` ```
## Tests password ## Tests password
@ -69,7 +73,9 @@ DSN_REMOTE_DATABASE="mysql:host=mariadb;port=3306;dbname=lasql;"
|test1@test.com| 8ad4025044b77ae6a5e3fcf99e53e44b15db9a4ecf468be21cbc6b9fbdae6d9f| cesaltestunexemple| Locke|John| |test1@test.com| 8ad4025044b77ae6a5e3fcf99e53e44b15db9a4ecf468be21cbc6b9fbdae6d9f| cesaltestunexemple| Locke|John|
|test2@test.com| 50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d| NULL| Dubois| Angela| |test2@test.com| 50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d| NULL| Dubois| Angela|
|test3@test.com| 504ae1c3e2f5fdaf41f868164dabcef21e17059f5f388b452718a1ce92692c67| cesaltestunautreexemple| Dupont| Henri| |test3@test.com| 504ae1c3e2f5fdaf41f868164dabcef21e17059f5f388b452718a1ce92692c67| cesaltestunautreexemple| Dupont| Henri|
|test4@test.com| 50626fa21f45a275cea0efff13ff78fd02234cade322da08b7191c7e9150141d| NULL| Durand|Isabelle| |test4@test.com| $2a$12$zFN0VJ..Cuu.2itWQwmHJe5EUhNHazbMfCSJFpNiEfdwpLzjjDM0u| NULL| Durand|Isabelle|
A noter que le hash de test4 est en bcrypt
``` ```
### mariadb (sans salt) ### mariadb (sans salt)

View File

@ -36,9 +36,9 @@ class SecurityController extends AbstractController
$loginForm->get('password')->addError(new FormError($trans->trans('error.password', [], 'messages'))); $loginForm->get('password')->addError(new FormError($trans->trans('error.password', [], 'messages')));
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_PASSWORD); $request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_PASSWORD);
} }
if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_PDO)) { if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_SQL_LOGIN)) {
$loginForm->addError(new FormError($trans->trans('error.pdo', [], 'messages'))); $loginForm->addError(new FormError($trans->trans('error.sql_login', [], 'messages')));
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_PDO); $request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_SQL_LOGIN);
} }
} }

View File

@ -10,18 +10,18 @@ use Symfony\Component\DependencyInjection\Extension\Extension;
class SQLLoginExtension extends Extension implements CompilerPassInterface class SQLLoginExtension extends Extension implements CompilerPassInterface
{ {
/** @var array */ /** @var array */
protected $pdoConfig; protected $sqlLoginConfig;
public function load(array $configs, ContainerBuilder $container) public function load(array $configs, ContainerBuilder $container)
{ {
$configuration = new SQLLoginConfiguration(); $configuration = new SQLLoginConfiguration();
$config = $this->processConfiguration($configuration, $configs); $config = $this->processConfiguration($configuration, $configs);
$this->pdoConfig = $config; $this->sqlLoginConfig = $config;
} }
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
{ {
$definition = $container->getDefinition(SQLLoginRequest::class); $definition = $container->getDefinition(SQLLoginRequest::class);
$definition->replaceArgument('$config', $this->pdoConfig); $definition->replaceArgument('$config', $this->sqlLoginConfig);
} }
} }

View File

@ -0,0 +1,9 @@
<?php
namespace App\SQLLogin\Exception;
use Exception;
class InvalidSQLLoginAlgoException extends Exception
{
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\SQLLogin\Exception;
use Exception;
class InvalidSQLLoginConfigurationException extends Exception
{
}

View File

@ -30,7 +30,7 @@ class SQLLoginConnect extends AbstractController
* *
* @param void * @param void
* *
* @return PdoConnect * @return SQLLoginConnect
*/ */
public static function getInstance() public static function getInstance()
{ {

View File

@ -8,6 +8,7 @@ class SQLLoginRequest
public const LOGIN_COLUMN_NAME = 'login_column_name'; public const LOGIN_COLUMN_NAME = 'login_column_name';
public const SALT_COLUMN_NAME = 'salt_column_name'; public const SALT_COLUMN_NAME = 'salt_column_name';
public const PASSWORD_COLUMN_NAME = 'password_column_name'; public const PASSWORD_COLUMN_NAME = 'password_column_name';
public const PASSWORD_NEED_UPGRADE = 'password_need_upgrade';
public const TABLE_NAME = 'table_name'; public const TABLE_NAME = 'table_name';
protected array $config; protected array $config;
@ -23,36 +24,46 @@ class SQLLoginRequest
$this->password = $password; $this->password = $password;
} }
public function getDatabaseDsn() public function getDatabaseDsn(): string
{ {
return $this->dsn; return $this->dsn;
} }
public function getDbUser() public function getDbUser(): string
{ {
return $this->user; return $this->user;
} }
public function getDbPassword() public function getDbPassword(): string
{ {
return $this->password; return $this->password;
} }
public function getLoginColumnName() public function getLoginColumnName(): string
{ {
return $this->config[self::LOGIN_COLUMN_NAME]; return $this->config[self::LOGIN_COLUMN_NAME];
} }
public function egtPasswordColumnName() public function getPasswordColumnName(): string
{ {
return $this->config[self::PASSWORD_COLUMN_NAME]; return $this->config[self::PASSWORD_COLUMN_NAME];
} }
public function getSaltColumnName() public function getSaltColumnName(): ?string
{ {
return $this->config[self::SALT_COLUMN_NAME]; return $this->config[self::SALT_COLUMN_NAME];
} }
public function getTableName(): string
{
return $this->config[self::TABLE_NAME];
}
public function getDataToFetch(): array
{
return $this->config[self::DATA_TO_FETCH];
}
public function getRequestScope() public function getRequestScope()
{ {
$scope = ''; $scope = '';
@ -60,18 +71,32 @@ class SQLLoginRequest
$scope .= $data.','; $scope .= $data.',';
} }
$scope = substr($scope, 0, -1); $scope = substr($scope, 0, -1);
$request = 'SELECT '.$scope.' FROM '.$this->config[self::TABLE_NAME].' WHERE '.$this->config[self::LOGIN_COLUMN_NAME].' = :'.$this->config[self::LOGIN_COLUMN_NAME].';';
return $request; return 'SELECT '.$scope.' FROM '.$this->getTableName().' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
} }
/**
* Construction de la string pour la requête préparée selon la configuration yaml
* intègre la récupération du mot de passe hashé, du salt et de besoin d'upgrade de la méthode de hashage
*/
public function getRequestPassword() public function getRequestPassword()
{ {
$passwordColumns = $this->config[self::PASSWORD_COLUMN_NAME]; $fields = $this->getPasswordColumnName();
if (!empty($this->config[self::SALT_COLUMN_NAME])) { if (!empty($this->getSaltColumnName())) {
$passwordColumns .= ', '.$this->config[self::SALT_COLUMN_NAME]; $fields .= ', '.$this->getSaltColumnName();
} }
return 'SELECT '.$passwordColumns.' FROM '.$this->config[self::TABLE_NAME].' WHERE '.$this->config[self::LOGIN_COLUMN_NAME].' = :'.$this->config[self::LOGIN_COLUMN_NAME].';'; return 'SELECT '.$fields.' FROM '.$this->getTableName().' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
}
public function getRequestUpdatePassword()
{
$fieldsToUpdate = $this->getPasswordColumnName().'= :'.$this->getPasswordColumnName().',';
if (!empty($this->getSaltColumnName())) {
$fieldsToUpdate .= $this->getSaltColumnName().'= :'.$this->getSaltColumnName().',';
}
$fieldsToUpdate = substr($fieldsToUpdate, 0, -1);
return 'UPDATE '.$this->getTableName().' SET '.$fieldsToUpdate.' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
} }
} }

View File

@ -2,6 +2,8 @@
namespace App\Security\Hasher; namespace App\Security\Hasher;
use App\SQLLogin\Exception\InvalidSQLLoginAlgoException;
use App\SQLLogin\Exception\InvalidSQLLoginConfigurationException;
use App\SQLLogin\Exception\InvalidSQLPasswordException; use App\SQLLogin\Exception\InvalidSQLPasswordException;
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException; use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait; use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait;
@ -10,23 +12,37 @@ use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
class PasswordEncoder implements LegacyPasswordHasherInterface class PasswordEncoder implements LegacyPasswordHasherInterface
{ {
use CheckPasswordLengthTrait; use CheckPasswordLengthTrait;
protected ?string $pepper; public const PASSWORD_PATTERN = 'password';
protected string $hashAlgo; public const SALT_PATTERN = 'salt';
public const PEPPER_PATTERN = 'pepper';
public function __construct(?string $pepper, string $hashAlgo) protected ?string $pepper;
protected array $hashAlgoLegacy;
protected ?string $newHashAlgo;
protected array $securityPattern;
public function __construct(?string $pepper, string $hashAlgoLegacy, ?string $newHashAlgo, string $securityPattern)
{ {
$this->pepper = $pepper; $this->pepper = $pepper;
$this->hashAlgo = $hashAlgo; $this->hashAlgoLegacy = explode(',', $hashAlgoLegacy);
$this->newHashAlgo = $newHashAlgo;
$this->securityPattern = explode(',', $securityPattern);
} }
/**
* Utilise l'algo legacy
*/
public function hash(string $plainPassword, string $salt = null): string public function hash(string $plainPassword, string $salt = null): string
{ {
if ($this->isPasswordTooLong($plainPassword)) { if ($this->isPasswordTooLong($plainPassword)) {
throw new InvalidPasswordException(); throw new InvalidPasswordException();
} }
$hash = hash($this->hashAlgo, $plainPassword.$salt.$this->pepper); $completedPlainPassword = $this->getPasswordToHash($plainPassword, $salt);
if ($this->isObsoleteAlgo($this->newHashAlgo)) {
throw new InvalidSQLLoginAlgoException();
}
return $hash; return password_hash($completedPlainPassword, $this->getValidALgo($this->newHashAlgo));
} }
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
@ -35,7 +51,36 @@ class PasswordEncoder implements LegacyPasswordHasherInterface
return false; return false;
} }
if ($this->hash($plainPassword, $salt) === $hashedPassword) { $isNewest = password_get_info($hashedPassword)['algo'] === $this->newHashAlgo;
$completedPassword = $this->getPasswordToHash($plainPassword, $salt);
if ($isNewest) {
if (password_verify($completedPassword, $hashedPassword)) {
return true;
} else {
throw new InvalidSQLPasswordException();
}
}
// Si le mot de passe a besoin d'un rehash ou qu'il n'y a pas de nouvelle méthode indiquée, on sait qu'il faut utiliser l'une des méthodes legacy pour vérifier le mot de passe
if ($this->needsRehash($hashedPassword) || empty($this->newHashAlgo)) {
foreach ($this->hashAlgoLegacy as $algo) {
if ($this->isObsoleteAlgo($algo)) {
if (hash_equals(hash($algo, $completedPassword), $hashedPassword)) {
return true;
}
} else {
if (password_verify($completedPassword, $hashedPassword)) {
return true;
}
}
// On vérifie si la méthode legacy est obsolète, si oui on ne peut pas utiliser password_verify, on doit hasher et comparer
}
// si on on n'a pas encore retourné de résultat, le mot de passe doit être incorrect
throw new InvalidSQLPasswordException();
}
// Si on n'est pas rentré dans les conditions précedéntes, on peut utiliser password_verify
if (password_verify($completedPassword, $hashedPassword)) {
return true; return true;
} else { } else {
throw new InvalidSQLPasswordException(); throw new InvalidSQLPasswordException();
@ -44,6 +89,74 @@ class PasswordEncoder implements LegacyPasswordHasherInterface
public function needsRehash(string $hashedPassword): bool public function needsRehash(string $hashedPassword): bool
{ {
// Il y a besoin de tester si on veut mettre à jour le hashage de mot de passe uniquement si le nouveau algo de hashage est indiqué et qu'il est moderne (BCRYPT, ARGON, ...)
if (!empty($this->newHashAlgo) && !$this->isObsoleteAlgo($this->newHashAlgo)) {
return password_needs_rehash($hashedPassword, $this->getValidAlgo($this->newHashAlgo));
}
return false; return false;
} }
/**
* @param mixed $algo
*
* @return InvalidSQLLoginAlgoException|string
*/
public function getValidAlgo($algo)
{
if ($algo) {
if (in_array($algo, hash_algos())) {
return $algo;
}
$informalAlgos = [
'default' => PASSWORD_DEFAULT,
'bcrypt' => PASSWORD_BCRYPT,
'argon2i' => PASSWORD_ARGON2I,
'argon2id' => PASSWORD_ARGON2ID,
];
if (in_array($algo, array_keys($informalAlgos))) {
return $informalAlgos[$algo];
}
if (in_array($algo, password_algos())) {
return $algo;
}
throw new InvalidSQLLoginAlgoException('Invalid Algorythme');
}
}
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();
}
}
$completedArray = [];
foreach ($this->securityPattern as $term) {
$completedArray[] = $arrayRef[$term];
}
$completedPlainPassword = implode($completedArray);
return $completedPlainPassword;
}
} }

View File

@ -25,17 +25,17 @@ class SQLLoginUserAuthenticator extends AbstractAuthenticator
public const LOGIN_ROUTE = 'app_login'; public const LOGIN_ROUTE = 'app_login';
public const ERROR_LOGIN = 'error_login'; public const ERROR_LOGIN = 'error_login';
public const ERROR_PASSWORD = 'error_password'; public const ERROR_PASSWORD = 'error_password';
public const ERROR_PDO = 'error_pdo'; public const ERROR_SQL_LOGIN = 'error_sql_login';
protected string $baseUrl; protected string $baseUrl;
private SQLLoginService $pdoService; private SQLLoginService $sqlLoginService;
private UrlGeneratorInterface $router; private UrlGeneratorInterface $router;
private PasswordEncoder $passwordHasher; private PasswordEncoder $passwordHasher;
public function __construct(string $baseUrl, SQLLoginService $pdoService, UrlGeneratorInterface $router, PasswordEncoder $passwordHasher) public function __construct(string $baseUrl, SQLLoginService $sqlLoginService, UrlGeneratorInterface $router, PasswordEncoder $passwordHasher)
{ {
$this->baseUrl = $baseUrl; $this->baseUrl = $baseUrl;
$this->pdoService = $pdoService; $this->sqlLoginService = $sqlLoginService;
$this->router = $router; $this->router = $router;
$this->passwordHasher = $passwordHasher; $this->passwordHasher = $passwordHasher;
} }
@ -72,16 +72,21 @@ class SQLLoginUserAuthenticator extends AbstractAuthenticator
$rememberMe = isset($form['_remember_me']) ? true : false; $rememberMe = isset($form['_remember_me']) ? true : false;
try { try {
// requête préparée // requête préparée
list($remoteHashedPassword, $remoteSalt) = $this->pdoService->fetchPassword($login); list($remoteHashedPassword, $remoteSalt) = $this->sqlLoginService->fetchPassword($login);
} catch (PDOException $e) { } catch (PDOException $e) {
$request->getSession()->set(self::ERROR_PDO, true); $request->getSession()->set(self::ERROR_SQL_LOGIN, true);
throw new AuthenticationException(); throw new AuthenticationException();
} }
if ($remoteHashedPassword) { if ($remoteHashedPassword) {
try { try {
// Comparaison remote hash et hash du input password + salt // Comparaison remote hash et hash du input password + salt
// dump($remoteHashedPassword, $plaintextPassword, $remoteSalt, password_verify($plaintextPassword, $remoteHashedPassword));
$this->passwordHasher->verify($remoteHashedPassword, $plaintextPassword, $remoteSalt); $this->passwordHasher->verify($remoteHashedPassword, $plaintextPassword, $remoteSalt);
$attributes = $this->pdoService->fetchDatas($login); if ($this->passwordHasher->needsRehash($remoteHashedPassword)) {
$hash = $this->passwordHasher->hash($plaintextPassword);
$this->sqlLoginService->updatePassword($login, $hash, null);
}
$attributes = $this->sqlLoginService->fetchDatas($login);
$user = new User($login, $remoteHashedPassword, $attributes, $rememberMe); $user = new User($login, $remoteHashedPassword, $attributes, $rememberMe);
$loader = function (string $userIdentifier) use ($user) { $loader = function (string $userIdentifier) use ($user) {
@ -98,7 +103,7 @@ class SQLLoginUserAuthenticator extends AbstractAuthenticator
$request->getSession()->set(self::ERROR_PASSWORD, true); $request->getSession()->set(self::ERROR_PASSWORD, true);
throw new AuthenticationException(); throw new AuthenticationException();
} catch (PDOException $e) { } catch (PDOException $e) {
$request->getSession()->set(self::ERROR_PDO, true); $request->getSession()->set(self::ERROR_SQL_LOGIN, true);
throw new AuthenticationException(); throw new AuthenticationException();
} }
} }

View File

@ -4,7 +4,6 @@ namespace App\Security;
use App\Entity\User; use App\Entity\User;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserProviderInterface;
@ -13,10 +12,9 @@ class SQLLoginUserProvider implements UserProviderInterface
{ {
protected RequestStack $requestStack; protected RequestStack $requestStack;
public function __construct(RequestStack $requestStack, SessionInterface $session) public function __construct(RequestStack $requestStack)
{ {
$this->requestStack = $requestStack; $this->requestStack = $requestStack;
$this->session = $session;
} }
public function loadUserByIdentifier(string $identifier, ?User $user): ?UserInterface public function loadUserByIdentifier(string $identifier, ?User $user): ?UserInterface

View File

@ -56,12 +56,11 @@ class SQLLoginService extends AbstractController
$password = $query->fetch(PDO::FETCH_ASSOC); $password = $query->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) { } catch (PDOException $e) {
\Sentry\captureException($e); \Sentry\captureException($e);
dd($e);
throw new PDOException(); throw new PDOException();
} }
if ($password) { if ($password) {
return [ return [
$password[$this->sqlLoginRequest->egtPasswordColumnName()], $password[$this->sqlLoginRequest->getPasswordColumnName()],
isset($password[$this->sqlLoginRequest->getSaltColumnName()]) ? $password[$this->sqlLoginRequest->getSaltColumnName()] : null, isset($password[$this->sqlLoginRequest->getSaltColumnName()]) ? $password[$this->sqlLoginRequest->getSaltColumnName()] : null,
]; ];
} }
@ -69,11 +68,28 @@ class SQLLoginService extends AbstractController
return false; return false;
} }
public function updatePassword($login, $hashedPassword, $salt)
{
try {
$dbh = $this->getConnection();
$request = $this->sqlLoginRequest->getRequestUpdatePassword();
$query = $dbh->prepare($request);
$query->execute([
$this->sqlLoginRequest->getLoginColumnName() => $login,
$this->sqlLoginRequest->getPasswordColumnName() => $hashedPassword,
$this->sqlLoginRequest->getSaltColumnName() => $salt,
]);
} catch (PDOException $e) {
\Sentry\captureException($e);
throw new PDOException();
}
}
public function getConnection() public function getConnection()
{ {
// Appel du singleton // Appel du singleton
$pdo = SQLLoginConnect::getInstance(); $sqlLogin = SQLLoginConnect::getInstance();
// Connection bdd // Connection bdd
return $pdo->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword()); return $sqlLogin->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword());
} }
} }

View File

@ -1,4 +1,4 @@
error: error:
login: 'Incorrect login' login: 'Incorrect login'
password: 'Incorrect password' password: 'Incorrect password'
pdo: 'Connection to database encountered a problem' sql_login: 'Connection to database encountered a problem'

View File

@ -1,4 +1,4 @@
error: error:
login: 'Login incorrect ou inconnu' login: 'Login incorrect ou inconnu'
password: 'Mot de passe incorrect' password: 'Mot de passe incorrect'
pdo: 'La connexion à la base de données a rencontré un problème' sql_login: 'La connexion à la base de données a rencontré un problème'