Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS will be completely phased out by mid-2025. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 7ee8e102 authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

Pull request #202: Feature/EDELIVERY-8806 force change password expiration at exipation

Merge in EDELIVERY/smp from feature/EDELIVERY-8806-force-change-password-expiration-at-exipation to EDELIVERY-8907-ebcoreparty-identifier-in-xml-schema

* commit '1f5379f0e2e84c61a320b709e841a3f11c75425f':
  Update alerts for credentials verification and suspension
  Implement force change + warning before expire
parents b0cfc269 08e5e968
No related branches found
No related tags found
No related merge requests found
Showing
with 320 additions and 83 deletions
......@@ -25,6 +25,9 @@ eDelivery SMP 4.2
authentication.blueCoat.enabled - deprecated and replaced with smp.automation.authentication.external.tls.clientCert.enabled
smp.automation.authentication.external.tls.SSLClientCert.enabled Authentication with external module as: reverse proxy. Authenticated certificate is send to application using 'SSLClientCert' HTTP header. Do not enable this feature without properly configured reverse-proxy!
identifiersBehaviour.ParticipantIdentifierScheme.ebCoreId.concatenate: Concatenate ebCore party id in XML responses <ParticipantIdentifier >urn:oasis:names:tc:ebcore:partyid-type:unregistered:test-ebcore-id</ParticipantIdentifier>
smp.passwordPolicy.expired.forceChange: Force change password at UI login if expired
smp.passwordPolicy.warning.beforeExpiration: How many days before expiration should the UI warn users at login
- removed deprecated properties
bdmsl.integration.keystore.password
......
......@@ -10,7 +10,6 @@ import {Subscription} from "rxjs/internal/Subscription";
import {SmpInfo} from "../app-info/smp-info.model";
import {SmpConfig} from "../app-config/smp-config.model";
import {SecurityEventService} from "../security/security-event.service";
import {ExpiredPasswordDialogComponent} from "./expired-password-dialog/expired-password-dialog.component";
/**
* Purpose of object is to fetch lookups as domains and users
......
......@@ -58,7 +58,7 @@
</mat-card>
</form>
<table class="buttonsRow" >
<table class="buttonsRow" *ngIf="!this.forceChange">
<tr>
<td>
<button mat-raised-button color="primary" mat-dialog-close>
......
import {Component, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog';
import {
AbstractControl,
FormBuilder,
......@@ -16,6 +16,8 @@ import {UserDetailsService} from "../../user/user-details-dialog/user-details.se
import {CertificateRo} from "../../user/certificate-ro.model";
import {AlertMessageService} from "../alert-message/alert-message.service";
import {ErrorResponseRO} from "../error/error-model";
import {SecurityService} from "../../security/security.service";
import {InformationDialogComponent} from "../information-dialog/information-dialog.component";
@Component({
selector: 'smp-password-change-dialog',
......@@ -32,6 +34,7 @@ export class PasswordChangeDialogComponent {
current: User;
message: string;
messageType: string = "alert-error";
forceChange:boolean=false;
constructor(
public dialogRef: MatDialogRef<PasswordChangeDialogComponent>,
......@@ -39,10 +42,17 @@ export class PasswordChangeDialogComponent {
private lookups: GlobalLookups,
private userDetailsService: UserDetailsService,
private alertService: AlertMessageService,
private securityService: SecurityService,
public dialog: MatDialog,
private fb: FormBuilder
) {
// disable close of focus lost
dialogRef.disableClose = true;
this.current = {...data}
this.forceChange = this.current.forceChangeExpiredPassword;
let currentPasswdFormControl: FormControl = new FormControl({value: null, readonly: false}, [Validators.required]);
let newPasswdFormControl: FormControl = new FormControl({value: null, readonly: false},
[Validators.required, Validators.pattern(this.passwordValidationRegExp), equal(currentPasswdFormControl, false)]);
......@@ -83,13 +93,27 @@ export class PasswordChangeDialogComponent {
this.userDetailsService.changePassword(this.current.userId,
this.dialogForm.controls['new-password'].value,
this.dialogForm.controls['current-password'].value).subscribe((res: boolean) => {
this.showSuccessMessage("Password has been changed!")
this.showPassChangeDialog();
close()
},
(err) => {
this.showErrorMessage(err.error.errorDescription);
}
);
}
showPassChangeDialog(){
this.dialog.open(InformationDialogComponent, {
data: {
title: "Password changed!",
description: "Password has been successfully changed. Login again to the application with the new password!"
}
}).afterClosed().subscribe(result => {
// no need to logout because service itself logouts
this.securityService.finalizeLogout(result);
close();
})
}
showSuccessMessage(value: string) {
this.message = value;
this.messageType = "success";
......
......@@ -10,6 +10,10 @@ import {DefaultPasswordDialogComponent} from 'app/security/default-password-dial
import {Subscription} from 'rxjs';
import {ExpiredPasswordDialogComponent} from '../common/expired-password-dialog/expired-password-dialog.component';
import {GlobalLookups} from "../common/global-lookups";
import {PasswordChangeDialogComponent} from "../common/password-change-dialog/password-change-dialog.component";
import {UserDetailsDialogMode} from "../user/user-details-dialog/user-details-dialog.component";
import {InformationDialogComponent} from "../common/information-dialog/information-dialog.component";
import {DatePipe, formatDate} from "@angular/common";
@Component({
moduleId: module.id,
......@@ -23,6 +27,7 @@ export class LoginComponent implements OnInit, OnDestroy {
returnUrl: string;
sub: Subscription;
constructor(private route: ActivatedRoute,
private router: Router,
public lookups: GlobalLookups,
......@@ -37,9 +42,17 @@ export class LoginComponent implements OnInit, OnDestroy {
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
this.sub = this.securityEventService.onLoginSuccessEvent().subscribe(
data => {
if (data && data.passwordExpired) {
this.dialog.open(ExpiredPasswordDialogComponent).afterClosed().subscribe(() => this.router.navigate([this.returnUrl]));
user => {
if (user && user.passwordExpired) {
if (user.forceChangeExpiredPassword) {
this.dialog.open(PasswordChangeDialogComponent, {data: user}).afterClosed().subscribe(res =>
this.securityService.finalizeLogout(res)
);
} else {
this.dialog.open(ExpiredPasswordDialogComponent).afterClosed().subscribe(() => this.router.navigate([this.returnUrl]));
}
} else if (user?.showPasswordExpirationWarning) {
this.showWarningBeforeExpire(user);
} else {
this.router.navigate([this.returnUrl]);
}
......@@ -56,7 +69,7 @@ export class LoginComponent implements OnInit, OnDestroy {
const USER_INACTIVE = 'Inactive';
switch (error.status) {
case HTTP_UNAUTHORIZED:
message =error.error.errorDescription;
message = error.error.errorDescription;
this.model.password = '';
break;
case HTTP_FORBIDDEN:
......@@ -90,6 +103,15 @@ export class LoginComponent implements OnInit, OnDestroy {
this.securityService.login(this.model.username, this.model.password);
}
showWarningBeforeExpire(user: User) {
this.dialog.open(InformationDialogComponent, {
data: {
title: "Warning! Your password is about to expire!",
description: "Your password is about to expire on " + formatDate(user.passwordExpireOn,"longDate","en-US")+"! Please change the password before the expiration date!"
}
}).afterClosed().subscribe(() => this.router.navigate([this.returnUrl]));
}
verifyDefaultLoginUsed() {
const currentUser: User = this.securityService.getCurrentUser();
if (currentUser.defaultPasswordUsed) {
......@@ -97,15 +119,27 @@ export class LoginComponent implements OnInit, OnDestroy {
}
}
private convertWithMode(config) {
return (config && config.data)
? {
...config,
data: {
...config.data,
mode: config.data.mode || (config.data.edit ? UserDetailsDialogMode.EDIT_MODE : UserDetailsDialogMode.NEW_MODE)
}
}
: config;
}
ngOnDestroy(): void {
this.sub.unsubscribe();
}
isUserAuthSSOEnabled(): boolean {
return this.lookups.cachedApplicationInfo?.authTypes.includes('SSO');
return this.lookups.cachedApplicationInfo?.authTypes.includes('SSO');
}
isUserAuthPasswdEnabled():boolean {
isUserAuthPasswdEnabled(): boolean {
return this.lookups.cachedApplicationInfo?.authTypes.includes('PASSWORD');
}
}
......@@ -23,13 +23,13 @@ export class SecurityService {
login(username: string, password: string) {
let headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
return this.http.post<string>(SmpConstants.REST_PUBLIC_SECURITY_AUTHENTICATION,
return this.http.post<User>(SmpConstants.REST_PUBLIC_SECURITY_AUTHENTICATION,
JSON.stringify({
username: username,
password: password
}),
{ headers })
.subscribe((response: string) => {
.subscribe((response: User) => {
this.updateUserDetails(response);
},
(error: any) => {
......@@ -38,9 +38,10 @@ export class SecurityService {
}
refreshLoggedUserFromServer() {
let subject = new ReplaySubject<string>();
let subject = new ReplaySubject<User>();
this.getCurrentUsernameFromServer().subscribe((res: User) => {
this.getCurrentUsernameFromServer().subscribe((res: string) => {
this.updateUserDetails(res);
}, (error: any) => {
//console.log('getCurrentUsernameFromServer:' + error);
......@@ -50,22 +51,27 @@ export class SecurityService {
logout() {
this.http.delete(SmpConstants.REST_PUBLIC_SECURITY_AUTHENTICATION).subscribe((res: Response) => {
this.clearLocalStorage();
this.securityEventService.notifyLogoutSuccessEvent(res);
this.finalizeLogout(res);
},
(error) => {
this.securityEventService.notifyLogoutErrorEvent(error);
});
}
finalizeLogout(res){
this.clearLocalStorage();
this.securityEventService.notifyLogoutSuccessEvent(res);
}
getCurrentUser(): User {
return JSON.parse(this.readLocalStorage());
}
private getCurrentUsernameFromServer(): Observable<string> {
let subject = new ReplaySubject<string>();
this.http.get<string>(SmpConstants.REST_PUBLIC_SECURITY_USER)
.subscribe((res: string) => {
private getCurrentUsernameFromServer(): Observable<User> {
let subject = new ReplaySubject<User>();
this.http.get<User>(SmpConstants.REST_PUBLIC_SECURITY_USER)
.subscribe((res: User) => {
subject.next(res);
}, (error: any) => {
//console.log('getCurrentUsernameFromServer:' + error);
......@@ -78,7 +84,7 @@ export class SecurityService {
let subject = new ReplaySubject<boolean>();
if (callServer) {
//we get the username from the server to trigger the redirection to the login screen in case the user is not authenticated
this.getCurrentUsernameFromServer().subscribe((user: string) => {
this.getCurrentUsernameFromServer().subscribe((user: User) => {
if(!user) {
this.clearLocalStorage();
}
......@@ -130,9 +136,9 @@ export class SecurityService {
return subject.asObservable();
}
updateUserDetails(userDetails) {
this.populateLocalStorage(JSON.stringify(userDetails));
this.securityEventService.notifyLoginSuccessEvent(userDetails);
updateUserDetails(userDetails:User) {
this.populateLocalStorage(JSON.stringify(userDetails));
this.securityEventService.notifyLoginSuccessEvent(userDetails);
}
private populateLocalStorage(userDetails: string) {
......
......@@ -8,4 +8,7 @@ export interface User {
accessTokenExpireOn?: Date;
authorities: Array<Authority>;
defaultPasswordUsed: boolean;
forceChangeExpiredPassword?:boolean;
showPasswordExpirationWarning?:boolean;
passwordExpireOn?: Date;
}
......@@ -18,7 +18,7 @@ export class UserService {
) { }
updateUser(user: User) {
this.http.put<string>(SmpConstants.REST_PUBLIC_USER_UPDATE.replace('{user-id}', user.userId), user).subscribe(response => {
this.http.put<User>(SmpConstants.REST_PUBLIC_USER_UPDATE.replace('{user-id}', user.userId), user).subscribe(response => {
this.securityService.updateUserDetails(response);
this.alertService.success('The operation \'update user\' completed successfully.');
}, err => {
......
......@@ -51,17 +51,9 @@ public class DBUserToUserROConverter implements Converter<DBUser, UserRO> {
return target;
}
private boolean isPasswordExpired(DBUser source) {
return StringUtils.isNotEmpty(source.getPassword())
&& (isPasswordRecentlyReset(source) || isPasswordChangedLongerThanThreeMonthsAgo(source));
}
private boolean isPasswordRecentlyReset(DBUser source) {
return source.getPasswordChanged() == null;
}
private boolean isPasswordChangedLongerThanThreeMonthsAgo(DBUser source) {
return OffsetDateTime.now().minusMonths(3).isAfter(source.getPasswordChanged());
&& (source.getPasswordExpireOn() == null
|| OffsetDateTime.now().isAfter(source.getPasswordExpireOn()));
}
}
......@@ -10,9 +10,18 @@ import java.io.Serializable;
* @since 4.2
*/
public class PasswordChangeRO implements Serializable {
String username;
String currentPassword;
String newPassword;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCurrentPassword() {
return currentPassword;
}
......
......@@ -34,7 +34,9 @@ public class UserRO extends BaseRO implements UserDetails {
String userId;
CertificateRO certificate;
int statusPassword = EntityROStatus.PERSISTED.getStatusNumber();
boolean passwordExpired;
boolean passwordExpired = false;
boolean showPasswordExpirationWarning = false;
boolean forceChangeExpiredPassword =false;
/**
* Get DB user hash value. It can be used as unique ID for the user. Use hash value for the webservice/ui and do not
......@@ -147,6 +149,22 @@ public class UserRO extends BaseRO implements UserDetails {
this.statusPassword = statusPassword;
}
public boolean isShowPasswordExpirationWarning() {
return showPasswordExpirationWarning;
}
public void setShowPasswordExpirationWarning(boolean showPasswordExpirationWarning) {
this.showPasswordExpirationWarning = showPasswordExpirationWarning;
}
public boolean isForceChangeExpiredPassword() {
return forceChangeExpiredPassword;
}
public void setForceChangePassword(boolean forceChangeExpiredPassword) {
this.forceChangeExpiredPassword = forceChangeExpiredPassword;
}
@Override
@JsonIgnore
public boolean isAccountNonExpired() {
......
package eu.europa.ec.edelivery.smp.data.ui.enums;
public enum AlertSuspensionMomentEnum {
AT_LOGON,
WHEN_BLOCKED
}
\ No newline at end of file
......@@ -8,12 +8,12 @@ package eu.europa.ec.edelivery.smp.data.ui.enums;
*/
public enum AlertTypeEnum {
TEST_ALERT("test_mail.ftl"),
CREDENTIALS_IMMINENT_EXPIRATION("credentials_imminent_expiration.ftl"),
CREDENTIALS_EXPIRED("credentials_expired.ftl"),
ACCOUNT_SUSPENDED("account_suspended.ftl"),
CREDENTIAL_IMMINENT_EXPIRATION("credential_imminent_expiration.ftl"),
CREDENTIAL_EXPIRED("credential_expired.ftl"),
CREDENTIAL_SUSPENDED("credential_suspended.ftl"),
CREDENTIAL_VERIFICATION_FAILED("credential_verification_failed.ftl"),
;
private final String template;
AlertTypeEnum(String template) {
......
......@@ -70,6 +70,12 @@ public enum SMPPropertyEnum {
"The error message shown to the user in case the password does not follow the regex put in the domibus.passwordPolicy.pattern property", false, false,false, STRING),
PASSWORD_POLICY_VALID_DAYS("smp.passwordPolicy.validDays","90",
"Number of days password is valid", false, false,false, INTEGER),
PASSWORD_POLICY_UIWARNING_DAYS_BEFORE_EXPIRE("smp.passwordPolicy.warning.beforeExpiration","15",
"How many days before expiration should the UI warn users at login", false, false,false, INTEGER),
PASSWORD_POLICY_FORCE_CHANGE_EXPIRED("smp.passwordPolicy.expired.forceChange","true",
"Force change password at UI login if expired", false, false,false, BOOLEAN),
USER_MAX_FAILED_ATTEMPTS("smp.user.login.maximum.attempt","5",
"Number of console login attempt before the user is deactivated", false, false,false, INTEGER),
USER_SUSPENSION_TIME("smp.user.login.suspension.time","3600",
......@@ -111,6 +117,22 @@ public enum SMPPropertyEnum {
MAIL_SERVER_PASSWORD("mail.smtp.password", "", "smtp mail protocol - encrypted password for submitting the emails.", false,true,false, STRING),
MAIL_SERVER_PROPERTIES("mail.smtp.properties", "", " key:value properties separated with '|'.Ex: mail.smtp.auth:true|mail.smtp.starttls.enable:true|mail.smtp.quitwait:false.", false, false,false, MAP_STRING),
ALERT_USER_LOGIN_FAILURE_ENABLED("smp.alert.user.login_failure.enabled",
"false", "Enable/disable the login failure alert of the authentication module.", false, false,false, BOOLEAN),
ALERT_USER_LOGIN_FAILURE_LEVEL("smp.alert.user.login_failure.level",
"LOW", "Alert level for login failure.", false, false,false, STRING),
ALERT_USER_LOGIN_FAILURE_MAIL_SUBJECT("smp.alert.user.login_failure.mail.subject",
"Login failure", "Login failure mail subject. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_USER_SUSPENDED_ENABLED("smp.alert.user.suspended.enabled",
"true", "Enable/disable the login suspended alert of the authentication module.", false, false,false, BOOLEAN),
ALERT_USER_SUSPENDED_LEVEL("smp.alert.user.suspended.level",
"HIGH", "Alert level for login suspended. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_USER_SUSPENDED_MAIL_SUBJECT("smp.alert.user.suspended.mail.subject",
"Login credentials suspended", "Login suspended mail subject.", false, false,false, STRING),
ALERT_USER_SUSPENDED_MOMENT("smp.alert.user.suspended.mail.moment",
"WHEN_BLOCKED", "#When should the account disabled alert be triggered. Values: AT_LOGON: An alert will be triggered each time a user tries to login to a disabled account. WHEN_BLOCKED: An alert will be triggered once when the account got suspended.", false, false,false, STRING),
ALERT_PASSWORD_BEFORE_EXPIRATION_ENABLED("smp.alert.password.imminent_expiration.enabled",
"true", "Enable/disable the imminent password expiration alert", false, false,false, BOOLEAN),
ALERT_PASSWORD_BEFORE_EXPIRATION_PERIOD("smp.alert.password.imminent_expiration.delay_days",
......@@ -118,8 +140,8 @@ public enum SMPPropertyEnum {
ALERT_PASSWORD_BEFORE_EXPIRATION_INTERVAL("smp.alert.password.imminent_expiration.frequency_days",
"5", "Interval between alerts.", false, false,false, INTEGER),
ALERT_PASSWORD_BEFORE_EXPIRATION_LEVEL("smp.alert.password.imminent_expiration.level",
"LOW", "Password imminent expiration alert level.", false, false,false, STRING),
ALERT_PASSWORD_BEFORE_EXPIRATION_MAIL_SUBJECT("ssmp.alert.password.imminent_expiration.mail.subject",
"LOW", "Password imminent expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_PASSWORD_BEFORE_EXPIRATION_MAIL_SUBJECT("smp.alert.password.imminent_expiration.mail.subject",
"Password imminent expiration", "Password imminent expiration mail subject.", false, false,false, STRING),
ALERT_PASSWORD_EXPIRED_ENABLED("smp.alert.password.expired.enabled",
......@@ -129,7 +151,7 @@ public enum SMPPropertyEnum {
ALERT_PASSWORD_EXPIRED_INTERVAL("smp.alert.password.expired.frequency_days",
"5", "Frequency in days between alerts.", false, false,false, INTEGER),
ALERT_PASSWORD_EXPIRED_LEVEL("smp.alert.password.expired.level",
"LOW", "Password expiration alert level.", false, false,false, STRING),
"LOW", "Password expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_PASSWORD_EXPIRED_MAIL_SUBJECT("smp.alert.password.expired.mail.subject",
"Password expired", "Password expiration mail subject.", false, false,false, STRING),
......@@ -140,8 +162,8 @@ public enum SMPPropertyEnum {
ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_INTERVAL("smp.alert.accessToken.imminent_expiration.frequency_days",
"5", "Frequency in days between alerts.", false, false,false, INTEGER),
ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_LEVEL("smp.alert.accessToken.imminent_expiration.level",
"LOW", "AccessToken imminent expiration alert level.", false, false,false, STRING),
ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_MAIL_SUBJECT("ssmp.alert.accessToken.imminent_expiration.mail.subject",
"LOW", "AccessToken imminent expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_MAIL_SUBJECT("smp.alert.accessToken.imminent_expiration.mail.subject",
"Access token imminent expiration", "accessToken imminent expiration mail subject.", false, false,false, STRING),
ALERT_ACCESS_TOKEN_EXPIRED_ENABLED("smp.alert.accessToken.expired.enabled",
......@@ -151,7 +173,7 @@ public enum SMPPropertyEnum {
ALERT_ACCESS_TOKEN_EXPIRED_INTERVAL("smp.alert.accessToken.expired.frequency_days",
"5", "Frequency in days between alerts.", false, false,false, INTEGER),
ALERT_ACCESS_TOKEN_EXPIRED_LEVEL("smp.alert.accessToken.expired.level",
"LOW", "Access Token expiration alert level.", false, false,false, STRING),
"LOW", "Access Token expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_ACCESS_TOKEN_EXPIRED_MAIL_SUBJECT("smp.alert.accessToken.expired.mail.subject",
"Access token expired", "Password expiration mail subject.", false, false,false, STRING),
......@@ -162,8 +184,8 @@ public enum SMPPropertyEnum {
ALERT_CERTIFICATE_BEFORE_EXPIRATION_INTERVAL("smp.alert.certificate.imminent_expiration.frequency_days",
"5", "Frequency in days between alerts.", false, false,false, INTEGER),
ALERT_CERTIFICATE_BEFORE_EXPIRATION_LEVEL("smp.alert.certificate.imminent_expiration.level",
"LOW", "certificate imminent expiration alert level.", false, false,false, STRING),
ALERT_CERTIFICATE_BEFORE_EXPIRATION_MAIL_SUBJECT("ssmp.alert.certificate.imminent_expiration.mail.subject",
"LOW", "certificate imminent expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_CERTIFICATE_BEFORE_EXPIRATION_MAIL_SUBJECT("smp.alert.certificate.imminent_expiration.mail.subject",
"Certificate imminent expiration", "Certificate imminent expiration mail subject.", false, false,false, STRING),
ALERT_CERTIFICATE_EXPIRED_ENABLED("smp.alert.certificate.expired.enabled",
......@@ -173,7 +195,7 @@ public enum SMPPropertyEnum {
ALERT_CERTIFICATE_EXPIRED_INTERVAL("smp.alert.certificate.expired.frequency_days",
"5", "Frequency in days between alerts.", false, false,false, INTEGER),
ALERT_CERTIFICATE_EXPIRED_LEVEL("smp.alert.certificate.expired.level",
"LOW", "Certificate expiration alert level.", false, false,false, STRING),
"LOW", "Certificate expiration alert level. Values: {LOW, MEDIUM, HIGH}", false, false,false, STRING),
ALERT_CERTIFICATE_EXPIRED_MAIL_SUBJECT("smp.alert.certificate.expired.mail.subject",
"Certificate expired", "Password expiration mail subject.", false, false,false, STRING),
......
......@@ -11,6 +11,7 @@ import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.services.mail.MailService;
import eu.europa.ec.edelivery.smp.services.mail.PropertiesMailModel;
import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialSuspendedProperties;
import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialVerificationFailedProperties;
import eu.europa.ec.edelivery.smp.services.mail.prop.CredentialsExpirationProperties;
import eu.europa.ec.edelivery.smp.utils.HttpUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -51,7 +52,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertBeforeExpirePasswordMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertBeforeExpirePasswordLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_IMMINENT_EXPIRATION;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -70,7 +71,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertExpiredPasswordMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertExpiredPasswordLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_EXPIRED;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -91,7 +92,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertBeforeExpireAccessTokenMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertBeforeExpireAccessTokenLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_IMMINENT_EXPIRATION;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -112,7 +113,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertExpiredAccessTokenMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertExpiredAccessTokenLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_EXPIRED;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -134,7 +135,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertBeforeExpireCertificateMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertBeforeExpireCertificateLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_IMMINENT_EXPIRATION;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -155,7 +156,7 @@ public class AlertService {
// alert specific properties
String mailSubject = configurationService.getAlertExpiredCertificateMailSubject();
AlertLevelEnum alertLevel = configurationService.getAlertExpiredCertificateLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIALS_EXPIRED;
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_EXPIRED;
alertCredentialExpiration(mailSubject, mailTo,
credentialType, credentialId, expiredOn,
......@@ -209,33 +210,42 @@ public class AlertService {
alertDao.update(alert);
}
public void alertUsernamePasswordCredentialsSuspended(DBUser user) {
public void alertCredentialVerificationFailed(DBUser user,CredentialTypeEnum credentialType) {
Boolean loginFailureEnabled = configurationService.getAlertUserLoginFailureEnabled();
if (!loginFailureEnabled) {
LOG.debug("Alert Login failure is disabled!" );
return;
}
String mailTo = user.getEmailAddress();
String mailSubject = "User account is suspended";
AlertLevelEnum level = AlertLevelEnum.LOW;
AlertTypeEnum alertType = AlertTypeEnum.ACCOUNT_SUSPENDED;
String mailSubject = configurationService.getAlertBeforeUserSuspendedSubject();
AlertLevelEnum level = configurationService.getAlertUserSuspendedLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_VERIFICATION_FAILED;
Integer failureCount = user.getSequentialLoginFailureCount();
OffsetDateTime lastFailedLoginDate = user.getLastFailedLoginAttempt();
OffsetDateTime suspendedUtil = lastFailedLoginDate.plusSeconds(configurationService.getLoginSuspensionTimeInSeconds());
CredentialTypeEnum credentialType = CredentialTypeEnum.USERNAME_PASSWORD;
String credentialId = user.getUsername();
alertCredentialSuspended(mailSubject, mailTo,
alertCredentialVerificationFailed(mailSubject, mailTo,
credentialType, credentialId,
failureCount, lastFailedLoginDate, suspendedUtil,
failureCount, lastFailedLoginDate,
level, alertType);
}
public void alertAccessTokenCredentialsSuspended(DBUser user) {
public void alertCredentialsSuspended(DBUser user, CredentialTypeEnum credentialType) {
Boolean suspensionAlertEnabled = configurationService.getAlertUserSuspendedEnabled();
if (!suspensionAlertEnabled) {
LOG.debug("Alert suspended is disabled!" );
return;
}
String mailTo = user.getEmailAddress();
String mailSubject = "User access token is suspended";
AlertLevelEnum level = AlertLevelEnum.LOW;
AlertTypeEnum alertType = AlertTypeEnum.ACCOUNT_SUSPENDED;
Integer failureCount = user.getSequentialTokenLoginFailureCount();
OffsetDateTime lastFailedLoginDate = user.getLastTokenFailedLoginAttempt();
OffsetDateTime suspendedUtil = lastFailedLoginDate.plusSeconds(configurationService.getAccessTokenLoginSuspensionTimeInSeconds());
CredentialTypeEnum credentialType = CredentialTypeEnum.ACCESS_TOKEN;
String credentialId = user.getAccessTokenIdentifier();
String mailSubject = configurationService.getAlertBeforeUserSuspendedSubject();
AlertLevelEnum level = configurationService.getAlertUserSuspendedLevel();
AlertTypeEnum alertType = AlertTypeEnum.CREDENTIAL_SUSPENDED;
Integer failureCount = user.getSequentialLoginFailureCount();
OffsetDateTime lastFailedLoginDate = user.getLastFailedLoginAttempt();
OffsetDateTime suspendedUtil = lastFailedLoginDate.plusSeconds(configurationService.getLoginSuspensionTimeInSeconds());
String credentialId = user.getUsername();
alertCredentialSuspended(mailSubject, mailTo,
credentialType, credentialId,
......@@ -243,7 +253,42 @@ public class AlertService {
level, alertType);
}
public void alertCredentialVerificationFailed(String mailSubject,
String mailTo,
CredentialTypeEnum credentialType,
String credentialId,
Integer failedLoginCount,
OffsetDateTime lastFailedLoginDate,
AlertLevelEnum level,
AlertTypeEnum alertType) {
Boolean suspensionAlertEnabled = configurationService.getAlertUserLoginFailureEnabled();
if (!suspensionAlertEnabled) {
LOG.debug("Alert suspended is disabled!" );
return;
}
OffsetDateTime reportDate = OffsetDateTime.now();
String serverName = HttpUtils.getServerAddress();
DBAlert alert = new DBAlert();
alert.setProcessed(false);
alert.setMailSubject(mailSubject);
alert.setMailTo(mailTo);
alert.setReportingTime(reportDate);
alert.setAlertType(alertType);
alert.setAlertLevel(level);
alert.addProperty(CredentialVerificationFailedProperties.CREDENTIAL_TYPE.name(), credentialType.name());
alert.addProperty(CredentialVerificationFailedProperties.CREDENTIAL_ID.name(), credentialId);
alert.addProperty(CredentialVerificationFailedProperties.FAILED_LOGIN_ATTEMPT.name(), failedLoginCount.toString());
alert.addProperty(CredentialVerificationFailedProperties.LAST_LOGIN_FAILURE_DATETIME.name(), lastFailedLoginDate);
alert.addProperty(CredentialVerificationFailedProperties.REPORTING_DATETIME.name(), reportDate);
alert.addProperty(CredentialVerificationFailedProperties.ALERT_LEVEL.name(), level.name());
alert.addProperty(CredentialVerificationFailedProperties.SERVER_NAME.name(), serverName);
alertDao.persistFlushDetach(alert);
// submit alerts
submitAlertMail(alert);
}
public void alertCredentialSuspended(String mailSubject,
String mailTo,
CredentialTypeEnum credentialType,
......@@ -275,7 +320,6 @@ public class AlertService {
alertDao.persistFlushDetach(alert);
// submit alerts
submitAlertMail(alert);
}
}
......@@ -2,22 +2,17 @@ package eu.europa.ec.edelivery.smp.services;
import eu.europa.ec.edelivery.smp.auth.enums.SMPUserAuthenticationTypes;
import eu.europa.ec.edelivery.smp.data.dao.ConfigurationDao;
import eu.europa.ec.edelivery.smp.data.model.DBConfiguration;
import eu.europa.ec.edelivery.smp.data.ui.enums.AlertLevelEnum;
import eu.europa.ec.edelivery.smp.data.ui.enums.AlertSuspensionMomentEnum;
import eu.europa.ec.edelivery.smp.data.ui.enums.SMPPropertyEnum;
import eu.europa.ec.edelivery.smp.data.ui.enums.SMPPropertyTypeEnum;
import eu.europa.ec.edelivery.smp.exceptions.ErrorCode;
import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
import eu.europa.ec.edelivery.smp.logging.SMPLogger;
import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.utils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
......@@ -44,8 +39,9 @@ public class ConfigurationService {
}
public String getParticipantIdentifierSchemeRexExpMessage() {
return (String)configurationDAO.getCachedPropertyValue(PARTC_SCH_REGEXP_MSG);
return (String) configurationDAO.getCachedPropertyValue(PARTC_SCH_REGEXP_MSG);
}
public Boolean getForceConcatenateEBCorePartyId() {
Boolean value = (Boolean) configurationDAO.getCachedPropertyValue(PARTC_EBCOREPARTYID_CONCATENATE);
// true by default
......@@ -55,6 +51,7 @@ public class ConfigurationService {
public Pattern getPasswordPolicyRexExp() {
return (Pattern) configurationDAO.getCachedPropertyValue(PASSWORD_POLICY_REGULAR_EXPRESSION);
}
public String getPasswordPolicyRexExpPattern() {
return configurationDAO.getCachedProperty(PASSWORD_POLICY_REGULAR_EXPRESSION);
}
......@@ -66,14 +63,23 @@ public class ConfigurationService {
public Integer getPasswordPolicyValidDays() {
return (Integer) configurationDAO.getCachedPropertyValue(PASSWORD_POLICY_VALID_DAYS);
}
public Integer getPasswordPolicyUIWarningDaysBeforeExpire() {
return (Integer) configurationDAO.getCachedPropertyValue(PASSWORD_POLICY_UIWARNING_DAYS_BEFORE_EXPIRE);
}
public Boolean getPasswordPolicyForceChangeIfExpired() {
return (Boolean) configurationDAO.getCachedPropertyValue(PASSWORD_POLICY_FORCE_CHANGE_EXPIRED);
}
public Integer getAccessTokenPolicyValidDays() {
return (Integer) configurationDAO.getCachedPropertyValue(ACCESS_TOKEN_POLICY_VALID_DAYS);
}
public Integer getLoginMaxAttempts() {
return (Integer) configurationDAO.getCachedPropertyValue(USER_MAX_FAILED_ATTEMPTS);
}
public Integer getLoginSuspensionTimeInSeconds() {
return (Integer) configurationDAO.getCachedPropertyValue(USER_SUSPENSION_TIME);
}
......@@ -81,6 +87,7 @@ public class ConfigurationService {
public Integer getAccessTokenLoginMaxAttempts() {
return (Integer) configurationDAO.getCachedPropertyValue(ACCESS_TOKEN_MAX_FAILED_ATTEMPTS);
}
public Integer getAccessTokenLoginSuspensionTimeInSeconds() {
return (Integer) configurationDAO.getCachedPropertyValue(ACCESS_TOKEN_SUSPENSION_TIME);
}
......@@ -202,7 +209,7 @@ public class ConfigurationService {
}
public Pattern getSMLIntegrationServerCertSubjectRegExp() {
return (Pattern)configurationDAO.getCachedPropertyValue(SML_TLS_SERVER_CERT_SUBJECT_REGEXP);
return (Pattern) configurationDAO.getCachedPropertyValue(SML_TLS_SERVER_CERT_SUBJECT_REGEXP);
}
......@@ -298,17 +305,55 @@ public class ConfigurationService {
return (List<String>) configurationDAO.getCachedPropertyValue(AUTOMATION_AUTHENTICATION_TYPES);
}
//-----------------------
// before user suspended
public Boolean getAlertUserLoginFailureEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_USER_LOGIN_FAILURE_ENABLED);
}
public AlertLevelEnum getAlertUserLoginFailureLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_USER_LOGIN_FAILURE_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertBeforeUserLoginFailureSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_USER_LOGIN_FAILURE_MAIL_SUBJECT);
}
//-----------------------
// user suspended
public Boolean getAlertUserSuspendedEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_USER_SUSPENDED_ENABLED);
}
public AlertLevelEnum getAlertUserSuspendedLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_USER_SUSPENDED_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertBeforeUserSuspendedSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_USER_SUSPENDED_MAIL_SUBJECT);
}
public AlertSuspensionMomentEnum getAlertBeforeUserSuspendedAlertMoment() {
String moment = (String) configurationDAO.getCachedPropertyValue(ALERT_USER_SUSPENDED_MOMENT);
return AlertSuspensionMomentEnum.valueOf(moment);
}
//-----------------------
// before password expire
public Boolean getAlertBeforeExpirePasswordEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_BEFORE_EXPIRATION_ENABLED);
}
public Integer getAlertBeforeExpirePasswordPeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_BEFORE_EXPIRATION_PERIOD);
}
public Integer getAlertBeforeExpirePasswordInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_BEFORE_EXPIRATION_INTERVAL);
}
public AlertLevelEnum getAlertBeforeExpirePasswordLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_BEFORE_EXPIRATION_LEVEL);
return AlertLevelEnum.valueOf(level);
......@@ -322,12 +367,15 @@ public class ConfigurationService {
public Boolean getAlertExpiredPasswordEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_EXPIRED_ENABLED);
}
public Integer getAlertExpiredPasswordPeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_EXPIRED_PERIOD);
}
public Integer getAlertExpiredPasswordInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_EXPIRED_INTERVAL);
}
public AlertLevelEnum getAlertExpiredPasswordLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_PASSWORD_EXPIRED_LEVEL);
return AlertLevelEnum.valueOf(level);
......@@ -342,33 +390,42 @@ public class ConfigurationService {
public Boolean getAlertBeforeExpireAccessTokenEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_ENABLED);
}
public Integer getAlertBeforeExpireAccessTokenPeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_PERIOD);
}
public Integer getAlertBeforeExpireAccessTokenInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_INTERVAL);
}
public AlertLevelEnum getAlertBeforeExpireAccessTokenLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertBeforeExpireAccessTokenMailSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_BEFORE_EXPIRATION_MAIL_SUBJECT);
}
// expired access token alerts
public Boolean getAlertExpiredAccessTokenEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_EXPIRED_ENABLED);
}
public Integer getAlertExpiredAccessTokenPeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_EXPIRED_PERIOD);
}
public Integer getAlertExpiredAccessTokenInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_EXPIRED_INTERVAL);
}
public AlertLevelEnum getAlertExpiredAccessTokenLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_EXPIRED_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertExpiredAccessTokenMailSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_ACCESS_TOKEN_EXPIRED_MAIL_SUBJECT);
}
......@@ -378,33 +435,42 @@ public class ConfigurationService {
public Boolean getAlertBeforeExpireCertificateEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_BEFORE_EXPIRATION_ENABLED);
}
public Integer getAlertBeforeExpireCertificatePeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_BEFORE_EXPIRATION_PERIOD);
}
public Integer getAlertBeforeExpireCertificateInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_BEFORE_EXPIRATION_INTERVAL);
}
public AlertLevelEnum getAlertBeforeExpireCertificateLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_BEFORE_EXPIRATION_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertBeforeExpireCertificateMailSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_BEFORE_EXPIRATION_MAIL_SUBJECT);
}
// expired access token alerts
public Boolean getAlertExpiredCertificateEnabled() {
return (Boolean) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_ENABLED);
}
public Integer getAlertExpiredCertificatePeriod() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_PERIOD);
}
public Integer getAlertExpiredCertificateInterval() {
return (Integer) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_INTERVAL);
}
public AlertLevelEnum getAlertExpiredCertificateLevel() {
String level = (String) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_LEVEL);
return AlertLevelEnum.valueOf(level);
}
public String getAlertExpiredCertificateMailSubject() {
return (String) configurationDAO.getCachedPropertyValue(ALERT_CERTIFICATE_EXPIRED_MAIL_SUBJECT);
}
......
package eu.europa.ec.edelivery.smp.services.mail.prop;
public enum CredentialVerificationFailedProperties {
CREDENTIAL_TYPE,
CREDENTIAL_ID,
FAILED_LOGIN_ATTEMPT,
LAST_LOGIN_FAILURE_DATETIME,
REPORTING_DATETIME,
ALERT_LEVEL,
SERVER_NAME,
}
......@@ -59,7 +59,7 @@
<!-- TITLE -->
<tr>
<td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/>
Account is temporarly susspended</td>
Account is suspended</td>
</tr>
<!-- / TITLE -->
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment