diff --git a/changelog.txt b/changelog.txt index a3053448f6beebce1c67f537ba04748da61a4c87..ab1e1af5ac15a0ce31c2ecece509238aaaa4d805 100644 --- a/changelog.txt +++ b/changelog.txt @@ -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 diff --git a/smp-angular/src/app/common/global-lookups.ts b/smp-angular/src/app/common/global-lookups.ts index c4551e5fc3550a25043775be42279f61ef55ad27..faf29e10365a038bca9f8614befac33563503803 100644 --- a/smp-angular/src/app/common/global-lookups.ts +++ b/smp-angular/src/app/common/global-lookups.ts @@ -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 diff --git a/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.html b/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.html index 1078ed25caaa65ab889584603fb8f3c16ea7339d..b9d22ede280b54ef3b10890bbfedba20270ff590 100644 --- a/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.html +++ b/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.html @@ -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> diff --git a/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.ts b/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.ts index 1758ce316fd9d45a7e7f35078104895384487341..00251ef68765fe236d2648ffcfcae48515278eeb 100644 --- a/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.ts +++ b/smp-angular/src/app/common/password-change-dialog/password-change-dialog.component.ts @@ -1,5 +1,5 @@ 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"; diff --git a/smp-angular/src/app/login/login.component.ts b/smp-angular/src/app/login/login.component.ts index 37f6379e06b027cda08bb00728a179df79c7f60f..82d77a78fc36677e8c596c5ea4af76e7ee564423 100644 --- a/smp-angular/src/app/login/login.component.ts +++ b/smp-angular/src/app/login/login.component.ts @@ -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'); } } diff --git a/smp-angular/src/app/security/security.service.ts b/smp-angular/src/app/security/security.service.ts index 3e0ff844dde856984e1c7c28dd5dbef06414a648..43692c30fa27ab790d4d379dcf0e6420a1ec66ea 100644 --- a/smp-angular/src/app/security/security.service.ts +++ b/smp-angular/src/app/security/security.service.ts @@ -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) { diff --git a/smp-angular/src/app/security/user.model.ts b/smp-angular/src/app/security/user.model.ts index 40fe572ea159c59dea05c1b3223bec2b59a76c43..4fc85ce4a9e3eb66cde7fdc76213b7b29c7b0711 100644 --- a/smp-angular/src/app/security/user.model.ts +++ b/smp-angular/src/app/security/user.model.ts @@ -8,4 +8,7 @@ export interface User { accessTokenExpireOn?: Date; authorities: Array<Authority>; defaultPasswordUsed: boolean; + forceChangeExpiredPassword?:boolean; + showPasswordExpirationWarning?:boolean; + passwordExpireOn?: Date; } diff --git a/smp-angular/src/app/user/user.service.ts b/smp-angular/src/app/user/user.service.ts index 45e886e56a8b439abcc49ef03376c9f9af047839..eb3135ea9a234e2ca22abd8193199ea928b097f4 100644 --- a/smp-angular/src/app/user/user.service.ts +++ b/smp-angular/src/app/user/user.service.ts @@ -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 => { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverter.java index ae688eb84bd06c34c44d8d5d7fd0a5fd322d3fa9..db38ba15b997fa81ab3216a500ef481e865bb90d 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverter.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverter.java @@ -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())); } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/PasswordChangeRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/PasswordChangeRO.java index c00b5668f1065f6178d32efaaf7300750e8c2025..c6a1507ac43be93213e851ba836372ff7c0ee45a 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/PasswordChangeRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/PasswordChangeRO.java @@ -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; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java index 225a6296cd5b31df89f270dd0363b0c187be6c06..9472970873ceffaa4c9ecf0c800207c39461ebf8 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java @@ -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() { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertSuspensionMomentEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertSuspensionMomentEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..85c208fdb8a970b6cde5600f17e7c92802943aa7 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertSuspensionMomentEnum.java @@ -0,0 +1,6 @@ +package eu.europa.ec.edelivery.smp.data.ui.enums; + +public enum AlertSuspensionMomentEnum { + AT_LOGON, + WHEN_BLOCKED +} \ No newline at end of file diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java index 1785ee7aa68ce69b6549ed90165d62a7aa877e59..426cb5bc9b4548db98ba8a12655f6abab51cf0fe 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/AlertTypeEnum.java @@ -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) { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java index ecde8c414972b7b2a411e87f1e25885da9cb712a..8442ec4af076edfcbcf24345cfc7c45e813eefab 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java @@ -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), diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/AlertService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/AlertService.java index b47dd3badf8d17012058d2c88f164456799629b8..b16650985cba19200d27657cfda209757b401e42 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/AlertService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/AlertService.java @@ -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); - } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java index d2d58bd1e7663b450ce213457ae170fc1567f45e..c5b25fb48a368d632386d45394503c6f4f8be793 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java @@ -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); } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialVerificationFailedProperties.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialVerificationFailedProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..8c69cb39574c841c7aa062689b79475942e0b6c9 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/mail/prop/CredentialVerificationFailedProperties.java @@ -0,0 +1,11 @@ +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, +} diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credentials_expired.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_expired.ftl similarity index 100% rename from smp-server-library/src/main/resources/alert-mail-templates/credentials_expired.ftl rename to smp-server-library/src/main/resources/alert-mail-templates/credential_expired.ftl diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credentials_imminent_expiration.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_imminent_expiration.ftl similarity index 100% rename from smp-server-library/src/main/resources/alert-mail-templates/credentials_imminent_expiration.ftl rename to smp-server-library/src/main/resources/alert-mail-templates/credential_imminent_expiration.ftl diff --git a/smp-server-library/src/main/resources/alert-mail-templates/account_suspended.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl similarity index 98% rename from smp-server-library/src/main/resources/alert-mail-templates/account_suspended.ftl rename to smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl index 49df1e8bc7f6505c904280c4eda9866c98249dd0..53c653cf13f909294c90fae482451d8e2fba56e6 100644 --- a/smp-server-library/src/main/resources/alert-mail-templates/account_suspended.ftl +++ b/smp-server-library/src/main/resources/alert-mail-templates/credential_suspended.ftl @@ -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 --> diff --git a/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl b/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl new file mode 100644 index 0000000000000000000000000000000000000000..9f3de0870dd7c9758cc1b93f61a9fe22e63e89af --- /dev/null +++ b/smp-server-library/src/main/resources/alert-mail-templates/credential_verification_failed.ftl @@ -0,0 +1,117 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<title>eDelivery SMP</title> +</head> +<body style="margin:0; padding:0; background-color: #f1f1f1;"> +<center> + <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;"> + <tr> + <td><!-- MARGIN TOP --> + + <table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f1f1f1;"> + <tr> + <td> </td> + </tr> + </table> + + <!-- / MARGIN TOP --> + + <table width="540" align="center" border="0" cellspacing="0" cellpadding="0"> + <tr> + <!-- MARGIN LEFT --> + <td width="20" valign="top"> </td> + <!-- / MARGIN LEFT --> + <td width="500" valign="top"><!-- WRAPPER --> + + <table width="500" border="0" cellpadding="0" cellspacing="0"> + <tr> + <td valign="top" style="border:5px solid #4cbdce;"><table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff;"> + <tr> + <!-- COL LEFT --> + <td width="20" valign="top"> </td> + <!-- / COL LEFT --> + + <!-- CENTER --> + <td width="460" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0"> + <tr> + <td height="20" valign="top"> </td> + </tr> + + <!-- TITLE --> + <tr> + <td valign="top" align="left" style=" font-size: 30px; font-family: Arial, Helvetica, sans-serif; color: #000;">eDelivery SMP<br/></td> + </tr> + <!-- / TITLE --> + + <!-- UNDERLINE --> + <tr> + <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0"> + <tr> + <td width="60" height="10" style="border-bottom:3px solid #4cbdce"></td> + <td width="400" height="5"></td> + </tr> + </table></td> + </tr> + <!-- / UNDERLINE --> + + <!-- TITLE --> + <tr> + <td valign="top" align="left" style=" font-size: 20px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/> + Account is temporarly suspended</td> + </tr> + <!-- / TITLE --> + + <!-- UNDERLINE --> + <tr> + <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0"> + <tr> + <td width="30" height="10" style="border-bottom:3px solid #000000"></td> + <td width="430" height="5"></td> + </tr> + </table></td> + </tr> + <!-- / UNDERLINE --> + + <!-- MAIN CONTENT --> + <tr> + <td valign="top" align="left" style=" font-size: 13px; font-family: Arial, Helvetica, sans-serif; color: #000;"><br/> + <br/> + <p><strong>Credential type:</strong> ${CREDENTIAL_TYPE}</p> + <p><strong>Credential id:</strong> ${CREDENTIAL_ID}</p> + <p><strong>Failed login attempt count:</strong> ${FAILED_LOGIN_ATTEMPT}</p> + <p><strong>Last failed login time:</strong> ${LAST_LOGIN_FAILURE_DATETIME}</p> + <p><strong>Reporting time:</strong> ${REPORTING_TIME}</p> + <p><strong>Alert level:</strong> ${ALERT_LEVEL}</p> + <p><strong>Server name:</strong> ${SERVER_NAME}</p> + </td> + </tr> + <!-- / MAIN CONTENT --> + + <tr> + <td height="20" valign="top"> </td> + </tr> + </table></td> + <!-- / CENTER --> + <!-- COL RIGHT --> + <td width="20" valign="top"> </td> + <!-- / COL RIGHT --> + </tr> + </table></td> + </tr> + </table> + + <!-- / WRAPPER --></td> + <!-- MARGIN RIGHT --> + <td width="20" valign="top"></td> + <!-- / MARGIN RIGHT --> + </tr> + </table> + + </td> + </tr> + </table> +</center> +</body> +</html> \ No newline at end of file diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverterTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverterTest.java index 57f51275ab82c4b95de036541a84e5948463f778..013a77085d17acd7db3f1548390f8662a2f0dda7 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverterTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/DBUserToUserROConverterTest.java @@ -46,7 +46,8 @@ public class DBUserToUserROConverterTest { whenConvertingTheExistingUser(); - thenThePasswordIsMarkedAsExpired("The passwords should be marked as expired when converting users having passwords that have been reset by SystemAdministrators"); + thenThePasswordIsMarkedAsExpired("The passwords should be marked as expired when converting users" + + " having passwords that have been reset by SystemAdministrators"); } @Test @@ -89,6 +90,7 @@ public class DBUserToUserROConverterTest { source.setCertificate(certificate); source.setPassword(password); source.setPasswordChanged(passwordChange); + source.setPasswordExpireOn(passwordChange!=null?passwordChange.plusMonths(3):null); } private void whenConvertingTheExistingUser() { diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AuditIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AuditIntegrationTest.java index 16aa479d1c6ad787215f427e33119f75d689b411..fdc3414a4f599b8297ddd682f58029ba0089256b 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AuditIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AuditIntegrationTest.java @@ -88,7 +88,7 @@ public class AuditIntegrationTest { DBAlert dbAlert = createDBAlert(); Map<String, Object> alterVal = new HashMap<>(); alterVal.put("processed", false); - alterVal.put("alertType", AlertTypeEnum.CREDENTIALS_IMMINENT_EXPIRATION); + alterVal.put("alertType", AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION); alterVal.put("alertStatus", AlertStatusEnum.FAILED); testAuditEntity(dbAlert, alterVal); } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java index 8e570b0ad6fa47512dc9f69ace40b16cbcbdfaf0..4e0bbf18f20dc605717c9800d8780d46ad0db5a2 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java @@ -25,7 +25,6 @@ public class TestDBUtils { return domain; } - public static DBDomain createDBDomain() { return createDBDomain(TestConstants.TEST_DOMAIN_CODE_1); } @@ -85,7 +84,7 @@ public class TestDBUtils { DBAlert dbalert = new DBAlert(); dbalert.setAlertLevel(AlertLevelEnum.MEDIUM); dbalert.setAlertStatus(AlertStatusEnum.SUCCESS); - dbalert.setAlertType(AlertTypeEnum.CREDENTIALS_IMMINENT_EXPIRATION); + dbalert.setAlertType(AlertTypeEnum.CREDENTIAL_IMMINENT_EXPIRATION); dbalert.setProcessed(true); dbalert.setProcessedTime(OffsetDateTime.now()); dbalert.setReportingTime(OffsetDateTime.now()); diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java index 7a3361afba3e9294a8376f41d6ec2a2d9a9cd0e3..308882b2683373b905524ae7a6e5354479fc61d5 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java @@ -6,6 +6,8 @@ import eu.europa.ec.edelivery.smp.data.dao.UserDao; import eu.europa.ec.edelivery.smp.data.model.DBCertificate; import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.data.ui.enums.AlertSuspensionMomentEnum; +import eu.europa.ec.edelivery.smp.data.ui.enums.CredentialTypeEnum; import eu.europa.ec.edelivery.smp.data.ui.enums.SMPPropertyEnum; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; @@ -244,6 +246,9 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { LOG.warn("User [{}] failed login attempt [{}]! did not reach the max failed attempts [{}]", user.getUsername(), user.getSequentialTokenLoginFailureCount(), configurationService.getAccessTokenLoginMaxAttempts()); return; } + if (configurationService.getAlertBeforeUserSuspendedAlertMoment() == AlertSuspensionMomentEnum.AT_LOGON) { + alertService.alertCredentialsSuspended(user, CredentialTypeEnum.ACCESS_TOKEN); + } LOG.securityWarn(SMPMessageCode.SEC_USER_SUSPENDED, user.getUsername()); throw new BadCredentialsException("The user is suspended. Please try again later or contact your administrator."); } @@ -311,7 +316,9 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, user.getUsername()); if (user.getSequentialTokenLoginFailureCount() >= configurationService.getAccessTokenLoginMaxAttempts()) { LOG.info("User access token [{}] failed sequential attempt exceeded the max allowed attempts [{}]!", user.getAccessToken(), configurationService.getAccessTokenLoginMaxAttempts()); - alertService.alertAccessTokenCredentialsSuspended(user); + alertService.alertCredentialsSuspended(user, CredentialTypeEnum.ACCESS_TOKEN); + } else { + alertService.alertCredentialVerificationFailed(user, CredentialTypeEnum.ACCESS_TOKEN); } throw new BadCredentialsException(LOGIN_FAILED_MESSAGE); } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderForUI.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderForUI.java index a140c7af6f1e412e52bfa707a26474752255ad39..d3de04a62646dedfda85d549a8c794eda56b27a2 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderForUI.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderForUI.java @@ -3,6 +3,8 @@ package eu.europa.ec.edelivery.smp.auth; import eu.europa.ec.edelivery.smp.data.dao.UserDao; import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.data.ui.enums.AlertSuspensionMomentEnum; +import eu.europa.ec.edelivery.smp.data.ui.enums.CredentialTypeEnum; import eu.europa.ec.edelivery.smp.data.ui.enums.SMPPropertyEnum; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; @@ -83,7 +85,6 @@ public class SMPAuthenticationProviderForUI implements AuthenticationProvider { LOG.debug("User with username does not exists [{}], continue with next authentication provider"); return null; } - user = oUsr.get(); } catch (AuthenticationException ex) { LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, username, ExceptionUtils.getRootCause(ex), ex); @@ -122,7 +123,9 @@ public class SMPAuthenticationProviderForUI implements AuthenticationProvider { LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, user.getUsername()); if (user.getSequentialLoginFailureCount() >= configurationService.getLoginMaxAttempts()) { LOG.info("User [{}] failed sequential attempt exceeded the max allowed attempts [{}]!", user.getUsername(), configurationService.getLoginMaxAttempts()); - alertService.alertUsernamePasswordCredentialsSuspended(user); + alertService.alertCredentialsSuspended(user, CredentialTypeEnum.USERNAME_PASSWORD); + } else { + alertService.alertCredentialVerificationFailed(user, CredentialTypeEnum.USERNAME_PASSWORD); } throw new BadCredentialsException("Login failed; Invalid userID or password"); } @@ -162,6 +165,9 @@ public class SMPAuthenticationProviderForUI implements AuthenticationProvider { LOG.warn("User [{}] failed login attempt [{}]! did not reach the max failed attempts [{}]", user.getUsername(), user.getSequentialLoginFailureCount(), configurationService.getLoginMaxAttempts()); return; } + if (configurationService.getAlertBeforeUserSuspendedAlertMoment() == AlertSuspensionMomentEnum.AT_LOGON) { + alertService.alertCredentialsSuspended(user, CredentialTypeEnum.USERNAME_PASSWORD); + } LOG.securityWarn(SMPMessageCode.SEC_USER_SUSPENDED, user.getUsername()); throw new BadCredentialsException("The user is suspended. Please try again later or contact your administrator."); } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java index 7c9e9da917ccd0063e3bb572622c143d6a5bb62d..992f9d13b608cab7be54a6edf0926e6e983120f6 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationService.java @@ -10,9 +10,17 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.CSRF_COOKIE_NAME; +import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.SESSION_COOKIE_NAME; + @Service public class SMPAuthenticationService { @@ -30,4 +38,18 @@ public class SMPAuthenticationService { SecurityContextHolder.getContext().setAuthentication(authentication); return authentication; } + + public void logout(HttpServletRequest request, HttpServletResponse response) { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null) { + LOG.debug("Cannot perform logout: no user is authenticated"); + return; + } + + LOG.info("Logging out user [{}]", auth.getName()); + new CookieClearingLogoutHandler(SESSION_COOKIE_NAME, CSRF_COOKIE_NAME).logout(request, response, null); + LOG.info("Cleared cookies"); + new SecurityContextLogoutHandler().logout(request, response, auth); + LOG.info("Logged out"); + } } \ No newline at end of file diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java index e27be3122be6e32fb127f0b64d81edaed3eb3722..92c8718db69aae7076503be925c7bea25e4fb899 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java @@ -85,7 +85,9 @@ public class SMPAuthorizationService { userRO.setPassword(""); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - userRO.setAuthorities(authentication.getAuthorities().stream().map(val -> (SMPAuthority) val).collect(Collectors.toList())); + if (authentication!=null ){ + userRO.setAuthorities(authentication.getAuthorities().stream().map(val -> (SMPAuthority) val).collect(Collectors.toList())); + } return userRO; } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java index c5b41f8122cecd6f7c34417bb4c5f10f54aad09c..374eca0350699e024d4157ecd700b30b583ebac1 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java @@ -5,7 +5,6 @@ import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationService; import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationToken; import eu.europa.ec.edelivery.smp.auth.SMPAuthorizationService; import eu.europa.ec.edelivery.smp.data.model.DBUser; -import eu.europa.ec.edelivery.smp.data.ui.ErrorRO; import eu.europa.ec.edelivery.smp.data.ui.LoginRO; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.logging.SMPLogger; @@ -15,14 +14,9 @@ import eu.europa.ec.edelivery.smp.services.ui.UIUserService; import eu.europa.ec.edelivery.smp.utils.SMPCookieWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.ConversionService; -import org.springframework.http.HttpStatus; import org.springframework.security.access.annotation.Secured; import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler; -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.csrf.CsrfTokenRepository; import org.springframework.transaction.annotation.Transactional; @@ -31,9 +25,9 @@ import org.springframework.web.servlet.view.RedirectView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.time.OffsetDateTime; import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.*; -import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.CSRF_COOKIE_NAME; import static eu.europa.ec.edelivery.smp.utils.SMPCookieWriter.SESSION_COOKIE_NAME; /** @@ -87,23 +81,14 @@ public class AuthenticationResource { csrfTokenRepository.saveToken(csfrToken, request, response); SMPAuthenticationToken authentication = (SMPAuthenticationToken) authenticationService.authenticate(loginRO.getUsername(), loginRO.getPassword()); - UserRO userRO = conversionService.convert(authentication.getUser(), UserRO.class); - return authorizationService.sanitize(userRO); + DBUser user = authentication.getUser(); + return getUserData(user); } @DeleteMapping(value = "authentication") public void logout(HttpServletRequest request, HttpServletResponse response) { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null) { - LOG.debug("Cannot perform logout: no user is authenticated"); - return; - } - - LOG.info("Logging out user [{}]", auth.getName()); - new CookieClearingLogoutHandler(SESSION_COOKIE_NAME, CSRF_COOKIE_NAME).logout(request, response, null); - LOG.info("Cleared cookies"); - new SecurityContextLogoutHandler().logout(request, response, auth); - LOG.info("Logged out"); + LOG.info("Logging out user for the session"); + authenticationService.logout(request, response); } /** @@ -123,11 +108,11 @@ public class AuthenticationResource { @GetMapping(value = "user") @Secured({S_AUTHORITY_TOKEN_SYSTEM_ADMIN, S_AUTHORITY_TOKEN_SMP_ADMIN, S_AUTHORITY_TOKEN_SERVICE_GROUP_ADMIN}) - public UserRO getUser() { + public UserRO getUser(HttpServletRequest request, HttpServletResponse response) { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserRO) { - return (UserRO) principal; + return getUpdatedUserData((UserRO) principal); } String username = (String) principal; @@ -138,8 +123,27 @@ public class AuthenticationResource { LOG.warn("User: [{}] does not exists anymore or is not active.", username); return null; } + return getUserData(user); + } + protected UserRO getUserData(DBUser user) { UserRO userRO = conversionService.convert(user, UserRO.class); + return getUpdatedUserData(userRO); + } + + /** + * Method updates data with "show expire dialog" flag, forces the password change flag and + * sanitize ui data/ + * @param userRO + * @return updated user data according to SMP configuration + */ + protected UserRO getUpdatedUserData(UserRO userRO) { + userRO.setShowPasswordExpirationWarning(userRO.getPasswordExpireOn() != null && + OffsetDateTime.now() + .minusDays(configurationService.getPasswordPolicyUIWarningDaysBeforeExpire()) + .isBefore(userRO.getPasswordExpireOn())); + + userRO.setForceChangePassword(userRO.isPasswordExpired() && configurationService.getPasswordPolicyForceChangeIfExpired()) ; return authorizationService.sanitize(userRO); } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java index 3cdd0772827fc972546cdcb9fb0e8238af8049fa..c166b98e979fc33bf20efb3fe8dcae5765b27535 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java @@ -1,5 +1,6 @@ package eu.europa.ec.edelivery.smp.ui.external; +import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationService; import eu.europa.ec.edelivery.smp.auth.SMPAuthorizationService; import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.AccessTokenRO; @@ -13,6 +14,9 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.MimeTypeUtils; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_USER; import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntityId; @@ -25,12 +29,15 @@ import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntit public class UserResource { private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UserResource.class); - - @Autowired - private UIUserService uiUserService; - @Autowired + protected UIUserService uiUserService; protected SMPAuthorizationService authorizationService; + protected SMPAuthenticationService authenticationService; + public UserResource(UIUserService uiUserService, SMPAuthorizationService authorizationService, SMPAuthenticationService authenticationService) { + this.uiUserService = uiUserService; + this.authorizationService = authorizationService; + this.authenticationService = authenticationService; + } @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userId)") @PostMapping(path = "/{user-id}/generate-access-token", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) @@ -43,10 +50,15 @@ public class UserResource { @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userId)") @PutMapping(path = "/{user-id}/change-password", consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public boolean changePassword(@PathVariable("user-id") String userId, @RequestBody PasswordChangeRO newPassword) { + public boolean changePassword(@PathVariable("user-id") String userId, @RequestBody PasswordChangeRO newPassword, HttpServletRequest request, HttpServletResponse response) { Long entityId = decryptEntityId(userId); LOG.info("Validating the password of the currently logged in user:[{}] with id:[{}] ", userId, entityId); - return uiUserService.updateUserPassword(entityId, newPassword.getCurrentPassword(), newPassword.getNewPassword()); + boolean result = uiUserService.updateUserPassword(entityId, newPassword.getCurrentPassword(), newPassword.getNewPassword()); + if (result){ + LOG.info("Password successfully changed. Logout the user, to be able to login with the new password!"); + authenticationService.logout(request, response); + } + return result; } /** diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceIntegrationTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c67efad7ae938b35de259aba4df2397054b992d0 --- /dev/null +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceIntegrationTest.java @@ -0,0 +1,102 @@ +package eu.europa.ec.edelivery.smp.ui; + +import eu.europa.ec.edelivery.smp.data.ui.UserRO; +import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.RequestPostProcessor; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.ContextLoaderListener; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.http.HttpSession; + +import static org.junit.Assert.assertNotNull; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; +import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +@RunWith(SpringRunner.class) +@WebAppConfiguration +@ContextConfiguration(classes = {SmpTestWebAppConfig.class}) +@Sql(scripts = { + "classpath:/cleanup-database.sql", + "classpath:/webapp_integration_test_data.sql"}, + executionPhase = BEFORE_TEST_METHOD) +public class AuthenticationResourceIntegrationTest { + + private static final String PATH = ResourceConstants.CONTEXT_PATH_PUBLIC_SECURITY + "/authentication"; + + @Autowired + private WebApplicationContext webAppContext; + + private MockMvc mvc; + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + + @Before + public void setup() { + mvc = MockMvcBuilders.webAppContextSetup(webAppContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + initServletContext(); + } + + private void initServletContext() { + MockServletContext sc = new MockServletContext(""); + ServletContextListener listener = new ContextLoaderListener(webAppContext); + ServletContextEvent event = new ServletContextEvent(sc); + } + + + @Test + public void authenticateSuccessTest() throws Exception { + + // given when + HttpSession session = mvc.perform(post(PATH) + .header("Content-Type", "application/json") + .content("{\"username\":\"smp_admin\",\"password\":\"test123\"}")) + .andExpect(status().isOk()).andReturn() + .getRequest() + .getSession(); + + assertNotNull(session); + } + + + @Test + public void authenticateInvalidPasswordTest() throws Exception { + // given when then + mvc.perform(post(PATH) + .header("Content-Type", "application/json") + .content("{\"username\":\"smp_admin\",\"password\":\"test1235\"}")) + .andExpect(status().isUnauthorized()).andReturn() + .getRequest() + .getSession(); + } + + @Test + public void authenticateInvalidUsernameTest() throws Exception { + + // given when + mvc.perform(post(PATH) + .header("Content-Type", "application/json") + .content("{\"username\":\"smp_admin1\",\"password\":\"test123\"}")) + .andExpect(status().isUnauthorized()).andReturn() + .getRequest() + .getSession(); + } +} \ No newline at end of file diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceTest.java index 7abdcd3836a37a878cdf1e3fb0806c6ff7fbcc0e..122f1cd94f512947a30485ebb97fdb530b82abcc 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResourceTest.java @@ -1,106 +1,93 @@ package eu.europa.ec.edelivery.smp.ui; -import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; -import org.junit.Before; -import org.junit.Ignore; +import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationService; +import eu.europa.ec.edelivery.smp.auth.SMPAuthorizationService; +import eu.europa.ec.edelivery.smp.data.ui.UserRO; +import eu.europa.ec.edelivery.smp.services.ConfigurationService; +import eu.europa.ec.edelivery.smp.services.ui.UIUserService; +import eu.europa.ec.edelivery.smp.utils.SMPCookieWriter; +import org.junit.Assert; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockServletContext; -import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.RequestPostProcessor; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.WebApplicationContext; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.http.HttpSession; - -import static org.junit.Assert.assertNotNull; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - - -@RunWith(SpringRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = {SmpTestWebAppConfig.class}) -@Sql(scripts = { - "classpath:/cleanup-database.sql", - "classpath:/webapp_integration_test_data.sql"}, - executionPhase = BEFORE_TEST_METHOD) -public class AuthenticationResourceTest { - - - private static final String PATH = ResourceConstants.CONTEXT_PATH_PUBLIC_SECURITY + "/authentication"; - - @Autowired - private WebApplicationContext webAppContext; +import org.mockito.Mockito; +import org.springframework.core.convert.ConversionService; +import org.springframework.security.web.csrf.CsrfTokenRepository; - private MockMvc mvc; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); +import java.time.OffsetDateTime; - @Before - public void setup() { - mvc = MockMvcBuilders.webAppContextSetup(webAppContext) - .apply(SecurityMockMvcConfigurers.springSecurity()) - .build(); - initServletContext(); - } +public class AuthenticationResourceTest { - private void initServletContext() { - MockServletContext sc = new MockServletContext(""); - ServletContextListener listener = new ContextLoaderListener(webAppContext); - ServletContextEvent event = new ServletContextEvent(sc); + SMPAuthenticationService authenticationService = Mockito.mock(SMPAuthenticationService.class); + SMPAuthorizationService authorizationService = Mockito.mock(SMPAuthorizationService.class); + ConversionService conversionService = Mockito.mock(ConversionService.class); + ConfigurationService configurationService = Mockito.mock(ConfigurationService.class); + SMPCookieWriter smpCookieWriter = Mockito.mock(SMPCookieWriter.class); + CsrfTokenRepository csrfTokenRepository = Mockito.mock(CsrfTokenRepository.class); + UIUserService uiUserService = Mockito.mock(UIUserService.class); + + AuthenticationResource testInstance= new AuthenticationResource(authenticationService, + authorizationService, + conversionService, + configurationService, + smpCookieWriter, + csrfTokenRepository, + uiUserService); + @Test + public void testGetUpdatedUserData() { + UserRO user = new UserRO(); + user.setPasswordExpireOn(OffsetDateTime.now().minusDays(1)); + Mockito.doReturn(10).when(configurationService).getPasswordPolicyUIWarningDaysBeforeExpire(); + Mockito.doReturn(false).when(configurationService).getPasswordPolicyForceChangeIfExpired(); + Mockito.doReturn(user).when(authorizationService).sanitize(Mockito.any()); + + user = testInstance.getUpdatedUserData(user); + + Assert.assertTrue(user.isShowPasswordExpirationWarning()); + Assert.assertFalse(user.isForceChangeExpiredPassword()); + Assert.assertFalse(user.isPasswordExpired()); } - @Test - public void authenticateSuccessTest() throws Exception { - - // given when - HttpSession session = mvc.perform(post(PATH) - .header("Content-Type", "application/json") - .content("{\"username\":\"smp_admin\",\"password\":\"test123\"}")) - .andExpect(status().isOk()).andReturn() - .getRequest() - .getSession(); - - assertNotNull(session); + public void testGetUpdatedUserDataDoNotShowWarning() { + UserRO user = new UserRO(); + user.setPasswordExpireOn(OffsetDateTime.now().minusDays(11)); + Mockito.doReturn(10).when(configurationService).getPasswordPolicyUIWarningDaysBeforeExpire(); + Mockito.doReturn(false).when(configurationService).getPasswordPolicyForceChangeIfExpired(); + Mockito.doReturn(user).when(authorizationService).sanitize(Mockito.any()); + + user = testInstance.getUpdatedUserData(user); + + Assert.assertFalse(user.isShowPasswordExpirationWarning()); + Assert.assertFalse(user.isForceChangeExpiredPassword()); + Assert.assertFalse(user.isPasswordExpired()); } - @Test - @Ignore - public void authenticateInvalidPasswordTest() throws Exception { - // given when then - mvc.perform(post(PATH) - .header("Content-Type", "application/json") - .content("{\"username\":\"smp_admin\",\"password\":\"test1235\"}")) - .andExpect(status().isForbidden()).andReturn() - .getRequest() - .getSession(); + public void testGetUpdatedUserDataForceChange() { + UserRO user = new UserRO(); + user.setPasswordExpireOn(OffsetDateTime.now().plusDays(1)); + user.setPasswordExpired(true); + Mockito.doReturn(10).when(configurationService).getPasswordPolicyUIWarningDaysBeforeExpire(); + Mockito.doReturn(true).when(configurationService).getPasswordPolicyForceChangeIfExpired(); + Mockito.doReturn(user).when(authorizationService).sanitize(Mockito.any()); + + user = testInstance.getUpdatedUserData(user); + + Assert.assertTrue(user.isForceChangeExpiredPassword()); + Assert.assertTrue(user.isPasswordExpired()); } @Test - @Ignore - public void authenticateInvalidUsernameTest() throws Exception { - - // given when - mvc.perform(post(PATH) - .header("Content-Type", "application/json") - .content("{\"username\":\"smp_admin1\",\"password\":\"test123\"}")) - .andExpect(status().isForbidden()).andReturn() - .getRequest() - .getSession(); - - + public void testGetUpdatedUserDataForceChangeFalse() { + UserRO user = new UserRO(); + user.setPasswordExpireOn(OffsetDateTime.now().plusDays(1)); + user.setPasswordExpired(true); + Mockito.doReturn(10).when(configurationService).getPasswordPolicyUIWarningDaysBeforeExpire(); + Mockito.doReturn(false).when(configurationService).getPasswordPolicyForceChangeIfExpired(); + Mockito.doReturn(user).when(authorizationService).sanitize(Mockito.any()); + + user = testInstance.getUpdatedUserData(user); + + Assert.assertFalse(user.isForceChangeExpiredPassword()); + Assert.assertTrue(user.isPasswordExpired()); } -} \ No newline at end of file +} diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceIntegrationTest.java similarity index 98% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceIntegrationTest.java index f9544cd37699c8bb51897b0a07ecee19aa4156ca..d8ddf8d7c0f97d64d72f16d26397f5f6743bef21 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ApplicationResourceIntegrationTest.java @@ -41,7 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "smp.artifact.version=TestApplicationVersion", "smp.artifact.build.time=2018-11-27 00:00:00", }) -public class ApplicationResourceTest { +public class ApplicationResourceIntegrationTest { private static final String PATH = ResourceConstants.CONTEXT_PATH_PUBLIC_APPLICATION; @Autowired diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java similarity index 98% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java index 21994aae6637bb6b54ace5ae57bba24096920d39..2bd62d5463d357e6451aaa8882f7a9f48f9ef870 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java @@ -39,7 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class DomainResourceTest { +public class DomainResourceIntegrationTest { private static final String PATH = ResourceConstants.CONTEXT_PATH_PUBLIC_DOMAIN; @Autowired diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceIntegrationTest.java similarity index 98% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceIntegrationTest.java index 87428f0db8a583bdbe6e28c9c37338ba33f5f9b6..5aaace5de71d01ab9a36b783251fa231cf7f30eb 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/SearchResourceIntegrationTest.java @@ -41,7 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class SearchResourceTest { +public class SearchResourceIntegrationTest { @Autowired private WebApplicationContext webAppContext; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceIntegrationTest.java similarity index 98% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceIntegrationTest.java index f956aa56f9b7705d99087890d841de3fff20cb54..4bc1007f04ba986b215d87810cc6eb1f7490769b 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceGroupResourceIntegrationTest.java @@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class ServiceGroupResourceTest { +public class ServiceGroupResourceIntegrationTest { @Autowired ServiceGroupDao serviceGroupDao; @@ -75,7 +75,7 @@ public class ServiceGroupResourceTest { .build(); initServletContext(); - validExtension = new String(IOUtils.toByteArray(ServiceGroupResourceTest.class.getResourceAsStream("/input/extensionMarshal.xml"))); + validExtension = new String(IOUtils.toByteArray(ServiceGroupResourceIntegrationTest.class.getResourceAsStream("/input/extensionMarshal.xml"))); } private void initServletContext() { diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceIntegrationTest.java similarity index 99% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceIntegrationTest.java index c433369a7f732a1e3dc51ebfa588df2bd0e20788..dffca393729a1069ee3dffc515b59c629a1fce9f 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/ServiceMetadataResourceIntegrationTest.java @@ -43,7 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class ServiceMetadataResourceTest { +public class ServiceMetadataResourceIntegrationTest { // For the following test data see the: webapp_integration_test_data.sql diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserResourceIntegrationTest.java similarity index 98% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserResourceIntegrationTest.java index bd85440e649af4c15fd1f636ab0835db878c7c65..eafcca60b5f9b9fcad2fe8d5111191d56fc87b36 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/UserResourceIntegrationTest.java @@ -1,4 +1,4 @@ -package eu.europa.ec.edelivery.smp.ui; +package eu.europa.ec.edelivery.smp.ui.external; import com.fasterxml.jackson.databind.ObjectMapper; import eu.europa.ec.edelivery.smp.data.ui.CertificateRO; @@ -6,6 +6,7 @@ import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; +import eu.europa.ec.edelivery.smp.ui.ResourceConstants; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class UserResourceTest { +public class UserResourceIntegrationTest { private static final String PATH_PUBLIC = ResourceConstants.CONTEXT_PATH_PUBLIC_USER; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceIntegrationTest.java similarity index 99% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceIntegrationTest.java index f28961785a5a5416a7b37928bce90945ce527584..4666c7a0e89266d1aa99f23d0ad2a5d142b8ae07 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/ApplicationAdminResourceIntegrationTest.java @@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "smp.artifact.version=TestApplicationVersion", "smp.artifact.build.time=2018-11-27 00:00:00", }) -public class ApplicationAdminResourceTest { +public class ApplicationAdminResourceIntegrationTest { private static final String PATH = ResourceConstants.CONTEXT_PATH_INTERNAL_APPLICATION; private static final RequestPostProcessor SMP_ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); private static final RequestPostProcessor SG_ADMIN_CREDENTIALS = httpBasic("sg_admin", "test123"); diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java similarity index 99% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java index 8b79c9816b7fb41cba73f34357db0f217177b430..f0870307ce0bcb6244cdd79f29baae78380e24b8 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java @@ -42,7 +42,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class DomainAdminResourceTest { +public class DomainAdminResourceIntegrationTest { private static final String PATH = ResourceConstants.CONTEXT_PATH_INTERNAL_DOMAIN; @Autowired diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java similarity index 99% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java index 9365a3bd236b8fec2d8a9d5e0950147cbdc8d77b..4fdab1e06f4d990f5e94576bdae30f429a10b16d 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/KeystoreResourceIntegrationTest.java @@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @Sql(scripts = { "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}) -public class KeystoreResourceTest { +public class KeystoreResourceIntegrationTest { private static final String PATH = CONTEXT_PATH_INTERNAL_KEYSTORE; Path keystore = Paths.get("src", "test", "resources", "keystores", "smp-keystore.jks"); diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java similarity index 94% rename from smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceTest.java rename to smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java index 5482126041af10f5e3bb6cc1a851368104936b8c..fb62cc4beae26c77aff1efc6ae581a1dc3be3dfe 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/TruststoreAdminResourceIntegrationTest.java @@ -8,7 +8,7 @@ import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.services.ui.UITruststoreService; import eu.europa.ec.edelivery.smp.test.SmpTestWebAppConfig; import eu.europa.ec.edelivery.smp.test.testutils.X509CertificateTestUtils; -import eu.europa.ec.edelivery.smp.ui.UserResourceTest; +import eu.europa.ec.edelivery.smp.ui.external.UserResourceIntegrationTest; import org.apache.commons.io.IOUtils; import org.hamcrest.CoreMatchers; import org.junit.Before; @@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "classpath:/cleanup-database.sql", "classpath:/webapp_integration_test_data.sql"}, executionPhase = BEFORE_TEST_METHOD) -public class TruststoreAdminResourceTest { +public class TruststoreAdminResourceIntegrationTest { private static final String PATH_INTERNAL = CONTEXT_PATH_INTERNAL_TRUSTSTORE; private static final String PATH_PUBLIC = CONTEXT_PATH_PUBLIC_TRUSTSTORE; @@ -84,7 +84,7 @@ public class TruststoreAdminResourceTest { @Test public void validateCertificateSystemAdmin() throws Exception { - byte[] buff = IOUtils.toByteArray(UserResourceTest.class.getResourceAsStream("/SMPtest.crt")); + byte[] buff = IOUtils.toByteArray(UserResourceIntegrationTest.class.getResourceAsStream("/SMPtest.crt")); // login MockHttpSession session = loginWithSMPAdmin(mvc); // when update data @@ -135,7 +135,7 @@ public class TruststoreAdminResourceTest { @Test public void uploadCertificateInvalidUser() throws Exception { - byte[] buff = IOUtils.toByteArray(UserResourceTest.class.getResourceAsStream("/SMPtest.crt")); + byte[] buff = IOUtils.toByteArray(UserResourceIntegrationTest.class.getResourceAsStream("/SMPtest.crt")); // id and logged user not match // given when mvc.perform(post(PATH_PUBLIC + "/34556655/validate-certificate") @@ -181,7 +181,7 @@ public class TruststoreAdminResourceTest { MockHttpSession session = loginWithSystemAdmin(mvc); UserRO userRO = getLoggedUserData(mvc, session); - byte[] buff = IOUtils.toByteArray(UserResourceTest.class.getResourceAsStream("/SMPtest.crt")); + byte[] buff = IOUtils.toByteArray(UserResourceIntegrationTest.class.getResourceAsStream("/SMPtest.crt")); int countStart = uiTruststoreService.getNormalizedTrustedList().size(); MvcResult prepRes = mvc.perform(post(PATH_INTERNAL + "/" + userRO.getUserId() + "/upload-certificate")