diff --git a/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.ts b/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.ts index a2c20e30e3244a615079deb97a1c62bb5b5efd59..3da5f58d4bc207b0db4fd519aff2e691aac3372d 100644 --- a/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.ts +++ b/smp-angular/src/app/common/dialogs/password-change-dialog/password-change-dialog.component.ts @@ -47,7 +47,7 @@ export class PasswordChangeDialogComponent { let currentPasswdFormControl: UntypedFormControl = new UntypedFormControl({value: null, readonly: false}, this.securityService.getCurrentUser().casAuthenticated && this.adminUser ? null : [Validators.required]); let newPasswdFormControl: UntypedFormControl = new UntypedFormControl({value: null, readonly: false}, - [Validators.required, Validators.pattern(this.passwordValidationRegExp), equal(currentPasswdFormControl, false)]); + [Validators.required, Validators.pattern(this.passwordValidationRegExp)]); let confirmNewPasswdFormControl: UntypedFormControl = new UntypedFormControl({value: null, readonly: false}, [Validators.required, equal(newPasswdFormControl, true)]); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java index 1c4d8c55ae32f6ae4f7b6fd2b221bd59f9c8c968..bf5c78633e4c00ff0b36e029e5250787b68382e6 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/enums/SMPPropertyEnum.java @@ -154,7 +154,7 @@ public enum SMPPropertyEnum { "Password minimum complexity rules!", OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, REGEXP), - PASSWORD_POLICY_MESSAGE("smp.passwordPolicy.validationMessage", "Minimum length: 16 characters;Maximum length: 32 characters;At least one letter in lowercase;At least one letter in uppercase;At least one digit;At least one special character", + PASSWORD_POLICY_MESSAGE("smp.passwordPolicy.validationMessage", "Minimum length: 16 characters;Maximum length: 32 characters;At least one letter in lowercase;At least one letter in uppercase;At least one digit;At least one special character;Must not be same as existing password", "The error message shown to the user in case the password does not follow the regex put in the domibus.passwordPolicy.pattern property", OPTIONAL, NOT_ENCRYPTED, NO_RESTART_NEEDED, STRING), PASSWORD_POLICY_VALID_DAYS("smp.passwordPolicy.validDays", "90", "Number of days password is valid", diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java index 62599cc6efa74b5a0cf87a0b399d10a5dd7645e0..829d4643346ba6dbcec76cc5313386890c803a9b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java @@ -246,6 +246,15 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { CredentialType.USERNAME_PASSWORD, CredentialTargetType.UI)); + // check if new password is the same as the old one + // but allow admin to overwrite it + if (!adminUpdate + && StringUtils.isNotBlank(dbCredential.getValue()) + && BCrypt.checkpw(password, dbCredential.getValue())) { + LOG.info(SMPLogger.SECURITY_MARKER, "Change/set password failed because 'new' password match the old password for user: [{}]", userID); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "PasswordChange", configurationService.getPasswordPolicyValidationMessage()); + } + dbCredential.setValue(BCryptPasswordHash.hashPassword(password)); OffsetDateTime currentTime = OffsetDateTime.now(); dbCredential.setChangedOn(currentTime); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java index 3ef1ec67c4fd874d7d478e0336d3c32012a8dc5f..fe9c78cb265e40f9a7ee877bf3c141ecd119cba3 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java @@ -250,6 +250,24 @@ class UIUserServiceIntegrationTest extends AbstractJunit5BaseDao { testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword); } + @Test + void testUpdateUserPasswordFaileSame() { + DBUser user = TestDBUtils.createDBUserByUsername(UUID.randomUUID().toString()); + DBCredential credential = TestDBUtils.createDBCredentialForUser(user, null, null, null); + credential.setValue(BCrypt.hashpw("TTTTtttt1111$$$$$", BCrypt.gensalt())); + userDao.persistFlushDetach(user); + credentialDao.persistFlushDetach(credential); + + long authorizedUserId = user.getId(); + long userToUpdateId = user.getId(); + String authorizedPassword = "TTTTtttt1111$$$$$"; + String newPassword = "TTTTtttt1111$$$$$"; + + SMPRuntimeException result = assertThrows(SMPRuntimeException.class, + () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword)); + MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Must not be same as existing password")); + } + @Test void testUpdateUserPasswordByAdminUserNotExists() { // system admin