From 8fce75c52deffd54d5c59418b9f2a7326c2b6c76 Mon Sep 17 00:00:00 2001 From: Damien <damien.burel@maarch.org> Date: Fri, 10 Apr 2020 18:01:42 +0200 Subject: [PATCH] FEAT #13667 TIME 1:35 Authentication locked and suspended informations --- .../controllers/AuthenticationController.php | 66 +++++++++++-------- src/core/models/AuthenticationModel.php | 53 --------------- src/core/models/CoreConfigModel.php | 14 +++- .../core/AuthenticationControllerTest.php | 28 +++++--- 4 files changed, 70 insertions(+), 91 deletions(-) diff --git a/src/core/controllers/AuthenticationController.php b/src/core/controllers/AuthenticationController.php index d74d1cf7b7f..b601c560edd 100755 --- a/src/core/controllers/AuthenticationController.php +++ b/src/core/controllers/AuthenticationController.php @@ -38,13 +38,13 @@ class AuthenticationController public function getInformations(Request $request, Response $response) { -// $path = CoreConfigModel::getConfigPath(); -// $hashedPath = md5($path); + $path = CoreConfigModel::getConfigPath(); + $hashedPath = md5($path); $appName = CoreConfigModel::getApplicationName(); $parameter = ParameterModel::getById(['id' => 'loginpage_message', 'select' => ['param_value_string']]); - return $response->withJson(['instanceId' => null, 'applicationName' => $appName, 'loginMessage' => $parameter['param_value_string'] ?? null]); + return $response->withJson(['instanceId' => $hashedPath, 'applicationName' => $appName, 'loginMessage' => $parameter['param_value_string'] ?? null]); } public static function authentication($authorizationHeaders = []) @@ -129,39 +129,37 @@ class AuthenticationController return ['isRouteAvailable' => true]; } - public static function handleFailedAuthentication(array $aArgs) + public static function handleFailedAuthentication(array $args) { - ValidatorModel::notEmpty($aArgs, ['userId']); - ValidatorModel::stringType($aArgs, ['userId']); + ValidatorModel::notEmpty($args, ['userId']); + ValidatorModel::intVal($args, ['userId']); $passwordRules = PasswordModel::getEnabledRules(); if (!empty($passwordRules['lockAttempts'])) { - $user = UserModel::getByLowerLogin(['select' => ['failed_authentication', 'locked_until'], 'login' => $aArgs['userId']]); - - if (!empty($user)) { - if (!empty($user['locked_until'])) { - $lockedDate = new \DateTime($user['locked_until']); - $currentDate = new \DateTime(); - if ($currentDate > $lockedDate) { - AuthenticationModel::resetFailedAuthentication(['userId' => $aArgs['userId']]); - $user['failed_authentication'] = 0; - } else { - return _ACCOUNT_LOCKED_UNTIL . " {$lockedDate->format('d/m/Y H:i')}"; - } - } + $user = UserModel::getById(['select' => ['failed_authentication', 'locked_until'], 'id' => $args['userId']]); + if (!empty($user['locked_until'])) { + return ['accountLocked' => true, 'lockedDate' => $user['locked_until']]; + } - AuthenticationModel::increaseFailedAuthentication(['userId' => $aArgs['userId'], 'tentatives' => $user['failed_authentication'] + 1]); + UserModel::update([ + 'set' => ['failed_authentication' => $user['failed_authentication'] + 1], + 'where' => ['id = ?'], + 'data' => [$args['userId']] + ]); - if (!empty($user['failed_authentication']) && ($user['failed_authentication'] + 1) >= $passwordRules['lockAttempts'] && !empty($passwordRules['lockTime'])) { - $lockedUntil = time() + 60 * $passwordRules['lockTime']; - AuthenticationModel::lockUser(['userId' => $aArgs['userId'], 'lockedUntil' => $lockedUntil]); - return _ACCOUNT_LOCKED_FOR . " {$passwordRules['lockTime']} mn"; - } + if (!empty($user['failed_authentication']) && ($user['failed_authentication'] + 1) >= $passwordRules['lockAttempts'] && !empty($passwordRules['lockTime'])) { + $lockedUntil = time() + 60 * $passwordRules['lockTime']; + UserModel::update([ + 'set' => ['locked_until' => date('Y-m-d H:i:s', $lockedUntil)], + 'where' => ['id = ?'], + 'data' => [$args['userId']] + ]); + return ['accountLocked' => true]; } } - return _BAD_LOGIN_OR_PSW; + return true; } public function authenticate(Request $request, Response $response) @@ -177,7 +175,18 @@ class AuthenticationController $login = strtolower($body['login']); $authenticated = AuthenticationModel::authentication(['login' => $login, 'password' => $body['password']]); if (empty($authenticated)) { - return $response->withStatus(401)->withJson(['errors' => 'Authentication Failed']); + $user = UserModel::getByLogin(['login' => $login, 'select' => ['id', 'status']]); + if (empty($user)) { + return $response->withStatus(401)->withJson(['errors' => 'Authentication Failed']); + } elseif ($user['status'] == 'SPD') { + return $response->withStatus(401)->withJson(['errors' => 'Account Suspended']); + } else { + $handle = AuthenticationController::handleFailedAuthentication(['userId' => $user['id']]); + if (!empty($handle['accountLocked'])) { + return $response->withStatus(401)->withJson(['errors' => 'Account Locked', 'date' => $handle['lockedDate'] ?? null]); + } + return $response->withStatus(401)->withJson(['errors' => 'Authentication Failed']); + } } $user = UserModel::getByLogin(['login' => $login, 'select' => ['id', 'loginmode', 'refresh_token', 'user_id']]); @@ -204,10 +213,11 @@ class AuthenticationController $refreshToken = AuthenticationController::getRefreshJWT(); $user['refresh_token'][] = $refreshToken; UserModel::update([ - 'set' => ['reset_token' => null, 'refresh_token' => json_encode($user['refresh_token'])], + 'set' => ['reset_token' => null, 'refresh_token' => json_encode($user['refresh_token']), 'failed_authentication' => 0, 'locked_until' => null], 'where' => ['id = ?'], 'data' => [$user['id']] ]); + $response = $response->withHeader('Token', AuthenticationController::getJWT()); $response = $response->withHeader('Refresh-Token', $refreshToken); diff --git a/src/core/models/AuthenticationModel.php b/src/core/models/AuthenticationModel.php index 9939b840192..ffde303a700 100755 --- a/src/core/models/AuthenticationModel.php +++ b/src/core/models/AuthenticationModel.php @@ -39,59 +39,6 @@ class AuthenticationModel return password_verify($args['password'], $aReturn[0]['password']); } - - public static function resetFailedAuthentication(array $aArgs) - { - ValidatorModel::notEmpty($aArgs, ['userId']); - ValidatorModel::stringType($aArgs, ['userId']); - - DatabaseModel::update([ - 'table' => 'users', - 'set' => [ - 'failed_authentication' => 0, - 'locked_until' => null, - ], - 'where' => ['lower(user_id) = lower(?)'], - 'data' => [$aArgs['userId']] - ]); - - return true; - } - - public static function increaseFailedAuthentication(array $aArgs) - { - ValidatorModel::notEmpty($aArgs, ['userId', 'tentatives']); - ValidatorModel::stringType($aArgs, ['userId']); - ValidatorModel::intVal($aArgs, ['tentatives']); - - DatabaseModel::update([ - 'table' => 'users', - 'set' => [ - 'failed_authentication' => $aArgs['tentatives'] - ], - 'where' => ['lower(user_id) = lower(?)'], - 'data' => [$aArgs['userId']] - ]); - - return true; - } - - public static function lockUser(array $aArgs) - { - ValidatorModel::notEmpty($aArgs, ['userId', 'lockedUntil']); - ValidatorModel::stringType($aArgs, ['userId']); - - DatabaseModel::update([ - 'table' => 'users', - 'set' => [ - 'locked_until' => date('Y-m-d H:i:s', $aArgs['lockedUntil']) - ], - 'where' => ['lower(user_id) = lower(?)'], - 'data' => [$aArgs['userId']] - ]); - - return true; - } public static function generatePassword() { diff --git a/src/core/models/CoreConfigModel.php b/src/core/models/CoreConfigModel.php index a484520157f..bb915e99e04 100755 --- a/src/core/models/CoreConfigModel.php +++ b/src/core/models/CoreConfigModel.php @@ -58,6 +58,18 @@ class CoreConfigModel return $customId; } + public static function getConfigPath() + { + $customId = CoreConfigModel::getCustomId(); + if (!empty($customId) && is_file("custom/{$customId}/apps/maarch_entreprise/xml/config.xml")) { + $path = "custom/{$customId}/apps/maarch_entreprise/xml/config.xml"; + } else { + $path = 'apps/maarch_entreprise/xml/config.xml'; + } + + return $path; + } + public static function getApplicationName() { static $applicationName; @@ -225,7 +237,7 @@ class CoreConfigModel $customId = CoreConfigModel::getCustomId(); - if (file_exists("custom/{$customId}/{$args['path']}")) { + if (is_file("custom/{$customId}/{$args['path']}")) { $path = "custom/{$customId}/{$args['path']}"; } else { $path = $args['path']; diff --git a/test/unitTests/core/AuthenticationControllerTest.php b/test/unitTests/core/AuthenticationControllerTest.php index 4ffc4095159..5ccee361f75 100755 --- a/test/unitTests/core/AuthenticationControllerTest.php +++ b/test/unitTests/core/AuthenticationControllerTest.php @@ -113,17 +113,27 @@ class AuthenticationControllerTest extends TestCase $fullRequest = \httpRequestCustom::addContentInBody(['rules' => $rules], $request); $passwordController->updateRules($fullRequest, new \Slim\Http\Response()); - $response = \SrcCore\models\AuthenticationModel::resetFailedAuthentication(['userId' => 'superadmin']); - $this->assertSame(true, $response); - + \User\models\UserModel::update([ + 'set' => ['failed_authentication' => 0, 'locked_until' => null], + 'where' => ['user_id = ?'], + 'data' => ['superadmin'] + ]); + for ($i = 1; $i < $lockAttempts; $i++) { - $response = \SrcCore\controllers\AuthenticationController::handleFailedAuthentication(['userId' => 'superadmin']); - $this->assertSame(_BAD_LOGIN_OR_PSW, $response); + $response = \SrcCore\controllers\AuthenticationController::handleFailedAuthentication(['userId' => $GLOBALS['id']]); + $this->assertSame(true, $response); } - $response = \SrcCore\controllers\AuthenticationController::handleFailedAuthentication(['userId' => 'superadmin']); - $this->assertSame(_ACCOUNT_LOCKED_FOR . " " . $lockTime . " mn", $response); - - $response = \SrcCore\models\AuthenticationModel::resetFailedAuthentication(['userId' => 'superadmin']); + $response = \SrcCore\controllers\AuthenticationController::handleFailedAuthentication(['userId' => $GLOBALS['id']]); + $this->assertSame(true, $response['accountLocked']); + $response = \SrcCore\controllers\AuthenticationController::handleFailedAuthentication(['userId' => $GLOBALS['id']]); + $this->assertSame(true, $response['accountLocked']); + $this->assertNotNull($response['lockedDate']); + + \User\models\UserModel::update([ + 'set' => ['failed_authentication' => 0, 'locked_until' => null], + 'where' => ['user_id = ?'], + 'data' => ['superadmin'] + ]); } } } -- GitLab