FEAT #12163 TIME 2:30 add routes to reset password

parent 1265f9f7
......@@ -13,6 +13,9 @@ DROP VIEW IF EXISTS res_view_letterbox;
DROP VIEW IF EXISTS res_view_attachments;
DROP VIEW IF EXISTS view_folders;
/*USERS*/
ALTER TABLE users DROP COLUMN IF EXISTS reset_token;
ALTER TABLE users ADD COLUMN reset_token text;
/* FULL TEXT */
DELETE FROM docservers where docserver_type_id = 'FULLTEXT';
......
......@@ -35,21 +35,21 @@
"zone.js": "^0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.803.17",
"@angular/animations": "^8.2.12",
"@angular-devkit/build-angular": "^0.803.19",
"@angular/animations": "^8.2.14",
"@angular/cdk": "^8.2.0",
"@angular/cli": "^8.3.17",
"@angular/common": "^8.2.12",
"@angular/compiler": "^8.2.12",
"@angular/compiler-cli": "^8.2.12",
"@angular/core": "^8.2.12",
"@angular/forms": "^8.2.12",
"@angular/cli": "^8.3.19",
"@angular/common": "^8.2.14",
"@angular/compiler": "^8.2.14",
"@angular/compiler-cli": "^8.2.14",
"@angular/core": "^8.2.14",
"@angular/forms": "^8.2.14",
"@angular/http": "^7.2.15",
"@angular/material": "^8.2.0",
"@angular/platform-browser": "^8.2.12",
"@angular/platform-browser-dynamic": "^8.2.12",
"@angular/platform-server": "^8.2.12",
"@angular/router": "^8.2.12",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"@angular/platform-server": "^8.2.14",
"@angular/router": "^8.2.14",
"@types/datatables.net": "^1.10.18",
"@types/jquery": "^2.0.53",
"@types/node": "^7.10.8",
......
......@@ -423,6 +423,8 @@ $app->delete('/users/{id}/signatures/{signatureId}', \User\controllers\UserContr
$app->post('/users/{id}/redirectedBaskets', \User\controllers\UserController::class . ':setRedirectedBaskets');
$app->delete('/users/{id}/redirectedBaskets', \User\controllers\UserController::class . ':deleteRedirectedBasket');
$app->put('/users/{id}/baskets', \User\controllers\UserController::class . ':updateBasketsDisplay');
$app->post('/password', \User\controllers\UserController::class . ':forgotPassword');
$app->put('/password', \User\controllers\UserController::class . ':updateForgottenPassword');
//VersionsUpdate
$app->get('/versionsUpdate', \VersionUpdate\controllers\VersionUpdateController::class . ':get');
......
......@@ -224,6 +224,7 @@ CREATE TABLE users
loginmode character varying(50) DEFAULT NULL::character varying,
cookie_key character varying(255) DEFAULT NULL::character varying,
cookie_date timestamp without time zone,
reset_token text,
failed_authentication INTEGER DEFAULT 0,
locked_until TIMESTAMP without time zone,
external_id jsonb DEFAULT '{}',
......
......@@ -19,10 +19,12 @@ use Basket\models\GroupBasketModel;
use Basket\models\RedirectBasketModel;
use Docserver\controllers\DocserverController;
use Docserver\models\DocserverModel;
use Entity\models\ListInstanceModel;
use Group\controllers\PrivilegeController;
use Email\controllers\EmailController;
use Entity\models\EntityModel;
use Entity\models\ListInstanceModel;
use Entity\models\ListTemplateModel;
use Firebase\JWT\JWT;
use Group\controllers\PrivilegeController;
use Group\models\GroupModel;
use History\controllers\HistoryController;
use History\models\HistoryModel;
......@@ -34,7 +36,9 @@ use Resource\models\ResModel;
use Respect\Validation\Validator;
use Slim\Http\Request;
use Slim\Http\Response;
use SrcCore\controllers\AuthenticationController;
use SrcCore\controllers\PasswordController;
use SrcCore\controllers\UrlController;
use SrcCore\models\AuthenticationModel;
use SrcCore\models\CoreConfigModel;
use SrcCore\models\DatabaseModel;
......@@ -1517,4 +1521,98 @@ class UserController
return true;
}
public function forgotPassword(Request $request, Response $response)
{
$body = $request->getParsedBody();
if (!Validator::stringType()->notEmpty()->validate($body['login'])) {
return $response->withStatus(400)->withJson(['errors' => 'Body login is empty']);
}
$user = UserModel::getByLogin(['select' => ['id', 'mail'], 'login' => strtolower($body['login'])]);
if (empty($user)) {
return $response->withStatus(204);
}
$GLOBALS['id'] = $user['id'];
$resetToken = AuthenticationController::getResetJWT();
UserModel::update(['set' => ['reset_token' => $resetToken], 'where' => ['id = ?'], 'data' => [$user['id']]]);
$url = UrlController::getCoreUrl() . '#/update-password?token=' . $resetToken;
EmailController::createEmail([
'userId' => $user['id'],
'data' => [
'sender' => ['email' => 'Notification'],
'recipients' => [$user['mail']],
'subject' => _NOTIFICATIONS_FORGOT_PASSWORD_SUBJECT,
'body' => _NOTIFICATIONS_FORGOT_PASSWORD_BODY . $url . _NOTIFICATIONS_FORGOT_PASSWORD_FOOTER,
'isHtml' => true,
'status' => 'WAITING'
]
]);
HistoryController::add([
'tableName' => 'users',
'recordId' => $body['login'],
'eventType' => 'UP',
'eventId' => 'userModification',
'info' => _PASSWORD_REINIT_SENT
]);
return $response->withStatus(204);
}
public static function updateForgottenPassword(Request $request, Response $response)
{
$body = $request->getParsedBody();
$check = Validator::stringType()->notEmpty()->validate($body['token']);
$check = $check && Validator::stringType()->notEmpty()->validate($body['password']);
if (!$check) {
return $response->withStatus(400)->withJson(['errors' => 'Body token or body password is empty']);
}
try {
$jwt = JWT::decode($body['token'], CoreConfigModel::getEncryptKey(), ['HS256']);
} catch (\Exception $e) {
return $response->withStatus(403)->withJson(['errors' => 'Invalid token', 'lang' => 'invalidToken']);
}
$user = UserModel::getById(['id' => $jwt->user->id, 'select' => ['user_id', 'id', 'reset_token']]);
if (empty($user)) {
return $response->withStatus(400)->withJson(['errors' => 'User does not exist']);
}
if ($body['token'] != $user['reset_token']) {
return $response->withStatus(403)->withJson(['errors' => 'Invalid token', 'lang' => 'invalidToken']);
}
if (!PasswordController::isPasswordValid(['password' => $body['password']])) {
return $response->withStatus(400)->withJson(['errors' => 'Password does not match security criteria']);
}
UserModel::update([
'set' => [
'password' => AuthenticationModel::getPasswordHash($body['password']),
'password_modification_date' => 'CURRENT_TIMESTAMP',
'reset_token' => null
],
'where' => ['id = ?'],
'data' => [$user['id']]
]);
$GLOBALS['id'] = $user['id'];
HistoryController::add([
'tableName' => 'users',
'recordId' => $user['user_id'],
'eventType' => 'UP',
'eventId' => 'userModification',
'info' => _PASSWORD_REINIT . " {$body['login']}"
]);
return $response->withStatus(204);
}
}
......@@ -14,6 +14,7 @@
namespace SrcCore\controllers;
use Firebase\JWT\JWT;
use SrcCore\models\AuthenticationModel;
use SrcCore\models\CoreConfigModel;
use SrcCore\models\PasswordModel;
......@@ -118,4 +119,18 @@ class AuthenticationController
return _BAD_LOGIN_OR_PSW;
}
public static function getResetJWT()
{
$token = [
'exp' => time() + 3600,
'user' => [
'id' => $GLOBALS['id']
]
];
$jwt = JWT::encode($token, CoreConfigModel::getEncryptKey());
return $jwt;
}
}
......@@ -408,3 +408,9 @@ define("_INDEXINGMODEL_MODIFICATION", "Indexing model modification");
define("_INDEXINGMODEL_SUPPRESSION", "Indexing model suppression");
define("_PRIORITY_DELAY_ALREADY_SET", "This time limit is already set to another priority");
define("_NOTIFICATIONS_FORGOT_PASSWORD_SUBJECT", "[Maarch Courrier] Reset password informations");
define("_NOTIFICATIONS_FORGOT_PASSWORD_BODY", "Hello,<br/>You requested to reset the password for your Maarch Courrier account.<br/>To change your password, please click on the link below :<br/>");
define("_NOTIFICATIONS_FORGOT_PASSWORD_FOOTER", "<br/><br/>If you did not perform this request, you can safely ignore this email.<br/>Please contact your administrator if you have any questions.");
define("_PASSWORD_REINIT_SENT", "Password reset sent");
define("_PASSWORD_REINIT", "Password rest");
......@@ -407,3 +407,9 @@ define("_INDEXINGMODEL_MODIFICATION", "Modèle d'enregistrement modifié");
define("_INDEXINGMODEL_SUPPRESSION", "Modèle d'enregistrement supprimé");
define("_PRIORITY_DELAY_ALREADY_SET", "Ce délai de traitement est déjà défini pour une autre priorité");
define("_NOTIFICATIONS_FORGOT_PASSWORD_SUBJECT", "[Maarch Courrier] Demande de réinitialisation de mot de passe");
define("_NOTIFICATIONS_FORGOT_PASSWORD_BODY", "Bonjour,<br/>Vous avez demandé à retrouver le mot de passe d'accès à votre compte Maarch Courrier.<br/>Pour modifier votre mot de passe, merci de bien vouloir cliquer sur le lien ci-dessous :<br/>");
define("_NOTIFICATIONS_FORGOT_PASSWORD_FOOTER", "<br/><br/>Si vous n'êtes pas à l'origine de cette demande, merci d'ignorer ce courriel.<br/>Pour toutes questions, merci de contacter l'administrateur technique de la solution.");
define("_PASSWORD_REINIT_SENT", "Réinitialisation du mot de passe envoyé");
define("_PASSWORD_REINIT", "Mot de passe réinitialisé");
......@@ -413,3 +413,9 @@ define("_INDEXINGMODEL_MODIFICATION", "Indexing model modification_TO_TRANSLATE"
define("_INDEXINGMODEL_SUPPRESSION", "Indexing model suppression_TO_TRANSLATE");
define("_PRIORITY_DELAY_ALREADY_SET", "Ce délai de traitement est déjà paramétré pour une autre priorité_TO_TRANSLATE");
define("_NOTIFICATIONS_FORGOT_PASSWORD_SUBJECT", "[Maarch Courrier] Reset password informations_TO_TRANSLATE");
define("_NOTIFICATIONS_FORGOT_PASSWORD_BODY", "Hello,<br/>You requested to reset the password for your Maarch Courrier account.<br/>To change your password, please click on the link below :<br/>_TO_TRANSLATE");
define("_NOTIFICATIONS_FORGOT_PASSWORD_FOOTER", "<br/><br/>If you did not perform this request, you can safely ignore this email.<br/>Please contact your administrator if you have any questions._TO_TRANSLATE");
define("_PASSWORD_REINIT_SENT", "Password reset sent_TO_TRANSLATE");
define("_PASSWORD_REINIT", "Password rest_TO_TRANSLATE");
......@@ -58,6 +58,7 @@ return array(
'Group\\' => array($baseDir . '/src/app/group'),
'Gitlab\\' => array($vendorDir . '/m4tthumphrey/php-gitlab-api/lib/Gitlab'),
'Folder\\' => array($baseDir . '/src/app/folder'),
'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
'ExternalSummary\\' => array($baseDir . '/src/app/external/summary'),
'ExternalSignatoryBook\\' => array($baseDir . '/src/app/external/externalSignatoryBook'),
......
......@@ -122,6 +122,7 @@ class ComposerStaticInitf21aebccfa6df888200dcb099aa69fbd
'F' =>
array (
'Folder\\' => 7,
'Firebase\\JWT\\' => 13,
'FastRoute\\' => 10,
),
'E' =>
......@@ -371,6 +372,10 @@ class ComposerStaticInitf21aebccfa6df888200dcb099aa69fbd
array (
0 => __DIR__ . '/../..' . '/src/app/folder',
),
'Firebase\\JWT\\' =>
array (
0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
),
'FastRoute\\' =>
array (
0 => __DIR__ . '/..' . '/nikic/fast-route/src',
......
......@@ -2667,5 +2667,53 @@
"tc-lib-barcode",
"upc"
]
},
{
"name": "firebase/php-jwt",
"version": "v5.0.0",
"version_normalized": "5.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
"reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": " 4.8.35"
},
"time": "2017-06-27T22:17:23+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt"
}
]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment