diff --git a/apps/maarch_entreprise/index.php b/apps/maarch_entreprise/index.php index adee7a99792d0b0531c2851dad820cabad4982fa..6134363a3bdcf2356a837e5d5963d77523baec2f 100755 --- a/apps/maarch_entreprise/index.php +++ b/apps/maarch_entreprise/index.php @@ -181,12 +181,13 @@ if (isset($_REQUEST['display'])) { if (empty($_REQUEST['triggerAngular'])) { if ($_REQUEST['page'] != 'login' && $_REQUEST['page'] != 'log' && $_REQUEST['page'] != 'logout' && !empty($_SESSION['user']['UserId'])) { $user = \User\models\UserModel::getByUserId(['userId' => $_SESSION['user']['UserId'], 'select' => ['password_modification_date', 'change_password', 'status']]); - $loggingMethod = \SrcCore\models\CoreConfigModel::getLoggingMethod(); - + if ($user['status'] == 'ABS') { header('location: '.$_SESSION['config']['businessappurl'].'index.php?triggerAngular=activateUser'); exit(); } + + $loggingMethod = \SrcCore\models\CoreConfigModel::getLoggingMethod(); if (!in_array($loggingMethod['id'], ['sso', 'cas', 'ldap', 'ozwillo'])) { $passwordRules = \SrcCore\models\PasswordModel::getEnabledRules(); if ($user['change_password'] == 'Y') { @@ -362,6 +363,7 @@ if (file_exists($path)) { $core->insert_page(); } ?> + <div id="loadingContent"></div> <my-app></my-app> </div> <p id="footer"> diff --git a/apps/maarch_entreprise/js/angular/app/password-modification.component.ts b/apps/maarch_entreprise/js/angular/app/password-modification.component.ts index faeff31e25bd13a4414bcdf8c234f51f693ab9b1..029a8aed7701bd3ad67a810e2bf46abf81cb65ac 100644 --- a/apps/maarch_entreprise/js/angular/app/password-modification.component.ts +++ b/apps/maarch_entreprise/js/angular/app/password-modification.component.ts @@ -18,38 +18,41 @@ declare var angularGlobals: any; }) export class PasswordModificationComponent implements OnInit { - private _mobileQueryListener: () => void; - mobileQuery: MediaQueryList; + private _mobileQueryListener : () => void; + mobileQuery : MediaQueryList; dialogRef : MatDialogRef<any>; config : any = {}; - coreUrl: string; - ruleText: string = ''; - otherRuleText: string; - lang: any = LANG; - loading: boolean = false; - user: any = {}; - hidePassword: Boolean = true; - - passLength: any = false; - passwordRules: any = { - minLength: { enabled: false, value: 0 }, - complexityUpper: { enabled: false, value: 0 }, - complexityNumber: { enabled: false, value: 0 }, - complexitySpecial: { enabled: false, value: 0 }, - renewal: { enabled: false, value: 0 }, - historyLastUse: {enabled:false, value:0}, + + coreUrl : string; + lang : any = LANG; + loading : boolean = false; + + user : any = {}; + ruleText : string = ''; + otherRuleText : string; + hidePassword : boolean = true; + passLength : any = false; + arrValidator : any[] = []; + validPassword : boolean = false; + matchPassword : boolean = false; + isLinear : boolean = false; + firstFormGroup : FormGroup; + + passwordRules : any = { + minLength : { enabled: false, value: 0 }, + complexityUpper : { enabled: false, value: 0 }, + complexityNumber : { enabled: false, value: 0 }, + complexitySpecial : { enabled: false, value: 0 }, + renewal : { enabled: false, value: 0 }, + historyLastUse : { enabled: false, value: 0 }, }; - passwordModel: any = { - currentPassword: "", - newPassword: "", - reNewPassword: "", + passwordModel : any = { + currentPassword : "", + newPassword : "", + reNewPassword : "", }; - arrValidator: any[] = []; - validPassword: Boolean = false; - matchPassword: Boolean = false; - isLinear = false; - firstFormGroup: FormGroup; + constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher, public http: HttpClient, private notify: NotificationService, private _formBuilder: FormBuilder, public dialog: MatDialog) { $j("link[href='merged_css.php']").remove(); @@ -59,19 +62,8 @@ export class PasswordModificationComponent implements OnInit { this.user = angularGlobals.user; } - regexValidator(regex: RegExp, error: ValidationErrors): ValidatorFn { - return (control: AbstractControl): { [key: string]: any } => { - if (!control.value) { - return null; - } - const valid = regex.test(control.value); - return valid ? null : error; - }; - } - prepare() { $j("link[href='merged_css.php']").remove(); - //$j('#header').remove(); $j('#footer').remove(); $j('#inner_content').remove(); $j('#inner_content_contact').parent('div').remove(); @@ -104,28 +96,20 @@ export class PasswordModificationComponent implements OnInit { valArr.push(Validators.required); data.rules.forEach((rule: any) => { - - if (rule.label == 'minLength') { this.passwordRules.minLength.enabled = rule.enabled; this.passwordRules.minLength.value = rule.value; - if (rule.enabled) { valArr.push(Validators.minLength(this.passwordRules.minLength.value)); ruleTextArr.push(rule.value + ' ' + this.lang['password' + rule.label]); } - - } else if (rule.label == 'complexityUpper') { this.passwordRules.complexityUpper.enabled = rule.enabled; this.passwordRules.complexityUpper.value = rule.value; - if (rule.enabled) { valArr.push(this.regexValidator(new RegExp('[A-Z]'), { 'complexityUpper': '' })); ruleTextArr.push(this.lang['password' + rule.label]); } - - } else if (rule.label == 'complexityNumber') { this.passwordRules.complexityNumber.enabled = rule.enabled; this.passwordRules.complexityNumber.value = rule.value; @@ -133,18 +117,13 @@ export class PasswordModificationComponent implements OnInit { valArr.push(this.regexValidator(new RegExp('[0-9]'), { 'complexityNumber': '' })); ruleTextArr.push(this.lang['password' + rule.label]); } - - } else if (rule.label == 'complexitySpecial') { this.passwordRules.complexitySpecial.enabled = rule.enabled; this.passwordRules.complexitySpecial.value = rule.value; - if (rule.enabled) { valArr.push(this.regexValidator(new RegExp('[^A-Za-z0-9]'), { 'complexitySpecial': '' })); ruleTextArr.push(this.lang['password' + rule.label]); } - - } else if (rule.label == 'renewal') { this.passwordRules.renewal.enabled = rule.enabled; this.passwordRules.renewal.value = rule.value; @@ -178,18 +157,26 @@ export class PasswordModificationComponent implements OnInit { '', Validators.compose([Validators.required]) ] - }, { - validator: this.matchValidator - }); + validator: this.matchValidator + }); } - matchValidator(group: FormGroup) { + regexValidator(regex: RegExp, error: ValidationErrors): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + if (!control.value) { + return null; + } + const valid = regex.test(control.value); + return valid ? null : error; + }; + } + matchValidator(group: FormGroup) { if (group.controls['newPasswordCtrl'].value == group.controls['retypePasswordCtrl'].value) { return false; } else { - group.controls['retypePasswordCtrl'].setErrors({'mismatch': true}) + group.controls['retypePasswordCtrl'].setErrors({'mismatch': true}); return {'mismatch': true}; } } @@ -202,21 +189,16 @@ export class PasswordModificationComponent implements OnInit { } if (this.firstFormGroup.controls['newPasswordCtrl'].hasError('required')) { return this.lang.requiredField + ' !'; - } else if (this.firstFormGroup.controls['newPasswordCtrl'].hasError('minlength') && this.passwordRules.minLength.enabled) { return this.passwordRules.minLength.value + ' ' + this.lang.passwordminLength + ' !'; - } else if (this.firstFormGroup.controls['newPasswordCtrl'].errors != null && this.firstFormGroup.controls['newPasswordCtrl'].errors.complexityUpper !== undefined && this.passwordRules.complexityUpper.enabled) { return this.lang.passwordcomplexityUpper + ' !'; - } else if (this.firstFormGroup.controls['newPasswordCtrl'].errors != null && this.firstFormGroup.controls['newPasswordCtrl'].errors.complexityNumber !== undefined && this.passwordRules.complexityNumber.enabled) { return this.lang.passwordcomplexityNumber + ' !'; - } else if (this.firstFormGroup.controls['newPasswordCtrl'].errors != null && this.firstFormGroup.controls['newPasswordCtrl'].errors.complexitySpecial !== undefined && this.passwordRules.complexitySpecial.enabled) { return this.lang.passwordcomplexitySpecial + ' !'; - } else { - this.firstFormGroup.controls['newPasswordCtrl'].setErrors(null) + this.firstFormGroup.controls['newPasswordCtrl'].setErrors(null); this.validPassword = true; return ''; } @@ -227,7 +209,7 @@ export class PasswordModificationComponent implements OnInit { this.passwordModel.newPassword = this.firstFormGroup.controls['newPasswordCtrl'].value; this.passwordModel.reNewPassword = this.firstFormGroup.controls['retypePasswordCtrl'].value; this.http.put(this.coreUrl + "rest/currentUser/password", this.passwordModel) - .subscribe((data: any) => { + .subscribe(() => { this.config = {data:{state:'END'},disableClose: true}; this.dialogRef = this.dialog.open(InfoChangePasswordModalComponent, this.config); }, (err: any) => { @@ -244,7 +226,8 @@ export class PasswordModificationComponent implements OnInit { templateUrl: "../../../Views/info-change-password-modal.component.html" }) export class InfoChangePasswordModalComponent { - lang: any = LANG; + + lang : any = LANG; constructor(public http: HttpClient, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef<InfoChangePasswordModalComponent>) { } diff --git a/apps/maarch_entreprise/js/angularFunctions.js b/apps/maarch_entreprise/js/angularFunctions.js index 3bd27e5cb3d39ae5834d61482449c7c779f8dd02..b8b154f94edaa6d0ee32542cf660ed3ee76f7867 100755 --- a/apps/maarch_entreprise/js/angularFunctions.js +++ b/apps/maarch_entreprise/js/angularFunctions.js @@ -8,7 +8,11 @@ function triggerAngular(locationToGo) { success: function(answer) { angularGlobals = answer; - $j('#inner_content').html('<i class="fa fa-spinner fa-spin fa-5x" style="margin-left: 50%;margin-top: 16%;font-size: 8em"></i>'); + if ($j('#inner_content').length > 0) { + $j('#inner_content').html('<i class="fa fa-spinner fa-spin fa-5x" style="margin-left: 50%;margin-top: 16%;font-size: 8em"></i>'); + } else { + $j('#loadingContent').html('<i class="fa fa-spinner fa-spin fa-5x" style="margin-left: 50%;margin-top: 16%;font-size: 8em"></i>'); + } if (!alreadyLoaded) { var head = document.getElementsByTagName('head')[0]; @@ -50,20 +54,6 @@ function changeLocationToAngular(locationToGo) { location.href = locationToGo; } -function successNotification(message) { - $j('#resultInfo').html(message).removeClass().addClass('alert alert-success alert-dismissible'); - $j("#resultInfo").fadeTo(3000, 500).slideUp(500, function() { - $j("#resultInfo").slideUp(500); - }); -} - -function errorNotification(message) { - $j('#resultInfo').html(message).removeClass().addClass('alert alert-danger alert-dismissible'); - $j("#resultInfo").fadeTo(3000, 500).slideUp(500, function() { - $j("#resultInfo").slideUp(500); - }); -} - function lockDocument(resId) { $j.ajax({ url: 'index.php?display=true&dir=actions&page=docLocker', diff --git a/rest/index.php b/rest/index.php index b06648294d7c379bb7f82a30376a7a6de8b15b4d..056c8b421ccb20deba13ed320b36828b7d4d7e22 100755 --- a/rest/index.php +++ b/rest/index.php @@ -34,6 +34,14 @@ $app->add(function (\Slim\Http\Request $request, \Slim\Http\Response $response, if (!empty($userId)) { $GLOBALS['userId'] = $userId; + $route = $request->getAttribute('route'); + if (!empty($route)) { + $currentRoute = $route->getPattern(); + $r = \SrcCore\controllers\AuthenticationController::isRouteAvailable(['userId' => $userId, 'currentRoute' => $currentRoute]); + if (!$r['isRouteAvailable']) { + return $response->withStatus(405)->withJson(['errors' => $r['errors']]); + } + } $response = $next($request, $response); return $response; } else { diff --git a/src/app/user/controllers/UserController.php b/src/app/user/controllers/UserController.php index d4146fcf53258200dbe86ec4d3b94074c25f1554..69d454a601d6d952b2daf1c253dd02a189eb4ff8 100644 --- a/src/app/user/controllers/UserController.php +++ b/src/app/user/controllers/UserController.php @@ -431,6 +431,9 @@ class UserController } $user = UserModel::getByUserId(['userId' => $aArgs['userId'], 'select' => ['status']]); + if (empty($user)) { + return $response->withStatus(400)->withJson(['errors' => 'User does not exist']); + } return $response->withJson(['status' => $user['status']]); } diff --git a/src/core/controllers/AuthenticationController.php b/src/core/controllers/AuthenticationController.php index 6fbbbbf4c5731b56dfe7c2702cfc6bec48f8e1d3..5104f2d351f52e0de970ff6d72810cb4fc4b66b5 100644 --- a/src/core/controllers/AuthenticationController.php +++ b/src/core/controllers/AuthenticationController.php @@ -15,6 +15,7 @@ namespace SrcCore\controllers; use SrcCore\models\AuthenticationModel; +use SrcCore\models\CoreConfigModel; use SrcCore\models\PasswordModel; use SrcCore\models\ValidatorModel; use User\models\UserModel; @@ -39,6 +40,42 @@ class AuthenticationController return $userId; } + public static function isRouteAvailable(array $aArgs) + { + ValidatorModel::notEmpty($aArgs, ['userId', 'currentRoute']); + ValidatorModel::stringType($aArgs, ['userId', 'currentRoute']); + + if ($aArgs['currentRoute'] != '/initialize') { + $user = UserModel::getByUserId(['select' => ['status', 'change_password'], 'userId' => $aArgs['userId']]); + + if ($user['status'] == 'ABS' && $aArgs['currentRoute'] != "/users/{id}/status") { + return ['isRouteAvailable' => false, 'errors' => 'User is ABS and must be activated']; + } + + if (!in_array($aArgs['currentRoute'], ['/passwordRules', '/currentUser/password'])) { + $loggingMethod = CoreConfigModel::getLoggingMethod(); + + if (!in_array($loggingMethod['id'], ['sso', 'cas', 'ldap', 'ozwillo'])) { + + $passwordRules = PasswordModel::getEnabledRules(); + if ($user['change_password'] == 'Y') { + return ['isRouteAvailable' => false, 'errors' => 'User must change his password']; + } elseif (!empty($passwordRules['renewal'])) { + $currentDate = new \DateTime(); + $lastModificationDate = new \DateTime($user['password_modification_date']); + $lastModificationDate->add(new \DateInterval("P{$passwordRules['renewal']}D")); + + if ($currentDate > $lastModificationDate) { + return ['isRouteAvailable' => false, 'errors' => 'User must change his password']; + } + } + } + } + } + + return ['isRouteAvailable' => true]; + } + public static function handleFailedAuthentication(array $aArgs) { ValidatorModel::notEmpty($aArgs, ['userId']);