diff --git a/changelog.txt b/changelog.txt index e95ccd24fd6cd6a1838a32a67883cd6e17b11463..0f6c13938319850d7317e8f9f352c3eadd3915ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -17,4 +17,5 @@ eDelivery SMP 4.2 smp.sso.cas.token.validation.params: The CAS token validation key:value properties separated with '|'.Ex: 'acceptStrengths:BASIC,CLIENT_CERT|assuranceLevel:TOP' smp.sso.cas.token.validation.groups: The '|' separated CAS groups user must belong to. smp.http.httpStrictTransportSecurity.maxAge: How long(in seconds) HSTS should last in the browser's cache(default one year) + smp.http.header.security.policy: Http header content security policy \ No newline at end of file diff --git a/smp-angular/README.md b/smp-angular/README.md new file mode 100644 index 0000000000000000000000000000000000000000..70da91d2351771fa20f7d3a09c5f91063f6b94d8 --- /dev/null +++ b/smp-angular/README.md @@ -0,0 +1,10 @@ +# SMP UI implementation +The module is SMP user frontend. + +# Development +For development use + + npm start + +Access the development pages via URL: +http://localhost:4200/#/ diff --git a/smp-angular/proxy-config.js b/smp-angular/proxy-config.js deleted file mode 100644 index 718d422ffe822557075754b43780252a010c86cc..0000000000000000000000000000000000000000 --- a/smp-angular/proxy-config.js +++ /dev/null @@ -1,18 +0,0 @@ -const PROXY_CONFIG = { - "/rest/search**": { - target: "http://localhost:8080/smp/ui/", - changeOrigin: true, - - secure: false, - logLevel: "debug", - // cookiePathRewrite: "/" // Doesn't work - onProxyRes: function (proxyRes, req, res) { - let cookies = proxyRes.headers["set-cookie"]; - if (cookies) { - proxyRes.headers["set-cookie"] = cookies.map(cookie => - cookie.replace("path=/smp/", "path=/").replace("Path=/smp/", "Path=/").replace("//", "/")); - } - }, - } -}; - diff --git a/smp-angular/proxy-config.json b/smp-angular/proxy-config.json new file mode 100644 index 0000000000000000000000000000000000000000..dc458d6f4ac03189d41aa649490f4f60bebc112a --- /dev/null +++ b/smp-angular/proxy-config.json @@ -0,0 +1,15 @@ +{ + "/rest/**": { + "target" : "http://localhost:8080/", + "secure" : "false", + "pathRewrite": { + "^/rest": "/smp/ui/rest" + }, + "logLevel": "debug", + "changeOrigin": true, + "cookiePathRewrite": { + "/smp": "/" + }, + "cookieDomainRewrite": "localhost" + } +} diff --git a/smp-angular/src/app/security/user.model.ts b/smp-angular/src/app/security/user.model.ts index ad02b6ce78a2a8bf254180a0f11137336233e911..929b76b6d4dfef350222ebd9a0030d61ab9bfce3 100644 --- a/smp-angular/src/app/security/user.model.ts +++ b/smp-angular/src/app/security/user.model.ts @@ -3,6 +3,7 @@ import {Authority} from "./authority.model"; export interface User { id: number; username: string; + accessTokenId?: string; authorities: Array<Authority>; defaultPasswordUsed: boolean; } diff --git a/smp-angular/src/app/user/access-token-ro.model.ts b/smp-angular/src/app/user/access-token-ro.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..c399755ffb79a973254633205c18f5d1f02feb2e --- /dev/null +++ b/smp-angular/src/app/user/access-token-ro.model.ts @@ -0,0 +1,5 @@ +export interface AccessTokenRo { + identifier: string; + value: string; + generatedOn?: Date; +} diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html index 12a771bafe04c3fa5bc5d866f35c9f0b8b957c7e..1f99018fb751233d02c8ef4bae86c6722a7100c6 100644 --- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html +++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html @@ -96,6 +96,32 @@ </mat-form-field> </div> </mat-card-content> + + <mat-card-title> + <mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['userToggle']" + (change)="onUserToggleChanged($event)" id="userAccessToken_id"> + User access token authentication + </mat-slide-toggle> + <div *ngIf="userForm.errors?.userDetailsOrCertificateRequired && (userForm.get('userToggle').dirty || userForm.get('certificateToggle').dirty)" + class="has-error">You need to generate access token + </div> + <button mat-raised-button color="primary" (click)="regenerateAccessToken()"> + <mat-icon>check_circle</mat-icon> + <span>Regenerate access token</span> + </button> + </mat-card-title> + + <mat-card-content> + <div class="panel" class="user-panel"> + <mat-form-field class="username"> + <input matInput placeholder="accessToken" [formControl]="userForm.controls['accessTokenId']" + id="accessToken_id" maxlength="255" /> + + </mat-form-field> + </div> + </mat-card-content> + + </mat-card> <mat-card fxFlex="60"> <mat-card-title> @@ -150,6 +176,7 @@ </label> </div> </mat-card-content> + </mat-card> </div> diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts index d1cfb3db3bcaac3bc05bb218163f8d61012b3103..6deed874c2f6c0b0824d0742ddcd611b95f6e899 100644 --- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts +++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts @@ -1,5 +1,5 @@ import {Component, Inject, ViewChild} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import { AbstractControl, @@ -23,6 +23,7 @@ import {Observable, of} from "rxjs"; import {catchError, map} from "rxjs/operators"; import {UserDetailsService} from "./user-details.service"; import {MatSlideToggleChange} from "@angular/material/slide-toggle"; +import {AccessTokenRo} from "../access-token-ro.model"; @Component({ selector: 'user-details-dialog', @@ -114,6 +115,7 @@ export class UserDetailsDialogComponent { } } + constructor(private dialogRef: MatDialogRef<UserDetailsDialogComponent>, private lookups: GlobalLookups, private certificateService: CertificateService, @@ -129,19 +131,19 @@ export class UserDetailsDialogComponent { this.current = this.editMode ? { ...data.row, - password: '', // ensures the user password is cleared before editing confirmation: '', - certificate: data.row.certificate? {...data.row.certificate} : this.newCertificateRo() + certificate: data.row.certificate ? {...data.row.certificate} : this.newCertificateRo() } : { active: true, username: '', + accessTokenId: '', emailAddress: '', password: '', confirmation: '', role: '', - encodedValue:'', - crlUrl:'', + encodedValue: '', + crlUrl: '', status: SearchTableEntityStatus.NEW, statusPassword: SearchTableEntityStatus.NEW, certificate: this.newCertificateRo(), @@ -175,8 +177,7 @@ export class UserDetailsDialogComponent { // improve notInList validator 'password': new FormControl({value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, [Validators.required, Validators.pattern(this.passwordPattern)]), - 'confirmation': new FormControl({value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, - Validators.pattern(this.passwordPattern)), + 'accessTokenId': new FormControl({value: ''}), // certificate authentication 'certificateToggle': new FormControl(this.current && this.current.certificate && !!this.current.certificate.certificateId), 'subject': new FormControl({value: '', disabled: true}, Validators.required), @@ -204,6 +205,7 @@ export class UserDetailsDialogComponent { // username/password authentication this.userForm.controls['username'].setValue(this.current.username); this.userForm.controls['password'].setValue(this.current.password); + this.userForm.controls['accessTokenId'].setValue(this.current.accessTokenId); // certificate authentication this.userForm.controls['subject'].setValue(this.current.certificate.subject); this.userForm.controls['validFrom'].setValue(this.current.certificate.validFrom); @@ -216,8 +218,8 @@ export class UserDetailsDialogComponent { this.userForm.controls['isCertificateValid'].setValue(!this.current.certificate.invalid); - this.certificateValidationMessage =this.current.certificate.invalidReason; - this.isCertificateInvalid= this.current.certificate.invalid; + this.certificateValidationMessage = this.current.certificate.invalidReason; + this.isCertificateInvalid = this.current.certificate.invalid; // if edit mode and user is given - toggle is disabled // username should not be changed.! @@ -230,6 +232,17 @@ export class UserDetailsDialogComponent { this.dialogRef.close(true); } + regenerateAccessToken() { + let accessTokenPromise: Promise<AccessTokenRo> = this.userDetailsService.regenerateAccessToken(this.userId, "AccessPassword"); + accessTokenPromise.then(response => { + this.alertService.success("Token with\n id: " + response.identifier + " and\nvalue: " + response.value + " was generated!") + this.userForm.patchValue({ + 'accessTokenId': response.identifier}) + }, err => { + this.alertService.error("Failed to generated access token. Please try again. If this happens again please contact Administrator!") + }); + } + uploadCertificate(event) { const file = event.target.files[0]; this.certificateService.uploadCertificate$(file).subscribe((res: CertificateRo) => { @@ -272,7 +285,7 @@ export class UserDetailsDialogComponent { this.userForm.controls['encodedValue'].setValue(this.tempStoreForCertificate.encodedValue); this.userForm.controls['crlUrl'].setValue(this.tempStoreForCertificate.crlUrl); this.certificateValidationMessage = this.tempStoreForCertificate.invalidReason; - this.isCertificateInvalid= this.tempStoreForCertificate.invalid; + this.isCertificateInvalid = this.tempStoreForCertificate.invalid; } else { // store data to temp, set values to null @@ -299,7 +312,7 @@ export class UserDetailsDialogComponent { this.userForm.controls['isCertificateValid'].setValue("true"); this.certificateValidationMessage = null; - this.isCertificateInvalid= false; + this.isCertificateInvalid = false; } } @@ -341,6 +354,7 @@ export class UserDetailsDialogComponent { this.current.active = this.userForm.get('active').value; this.current.emailAddress = this.userForm.get('emailAddress').value; this.current.role = this.userForm.get('role').value; + this.current.accessTokenId = this.userForm.controls['accessTokenId'].value; // certificate data if (this.userForm.get('certificateToggle')) { this.current.certificate.certificateId = this.userForm.controls['certificateId'].value; @@ -395,8 +409,8 @@ export class UserDetailsDialogComponent { serialNumber: '', certificateId: '', fingerprints: '', - crlUrl:'', - encodedValue:'', + crlUrl: '', + encodedValue: '', } } @@ -405,6 +419,7 @@ export class UserDetailsDialogComponent { id: null, index: null, username: '', + accessTokenId: '', emailAddress: '', role: '', active: true, diff --git a/smp-angular/src/app/user/user-details-dialog/user-details.service.ts b/smp-angular/src/app/user/user-details-dialog/user-details.service.ts index 221b7011ac05a5191105617802e82657559b7600..edc1db69c0339ddbbf34343bf45614fa29d637e7 100644 --- a/smp-angular/src/app/user/user-details-dialog/user-details.service.ts +++ b/smp-angular/src/app/user/user-details-dialog/user-details.service.ts @@ -3,15 +3,23 @@ import {HttpClient} from "@angular/common/http"; import {catchError, map} from "rxjs/operators"; import {SmpConstants} from "../../smp.constants"; import {Observable} from "rxjs"; +import {AccessTokenRo} from "../access-token-ro.model"; +import {AlertService} from "../../alert/alert.service"; @Injectable() export class UserDetailsService { constructor( private http: HttpClient, + private alertService: AlertService, ) { } isSamePreviousPasswordUsed$(userId: number, password: string): Observable<boolean> { return this.http.post<boolean>(`${SmpConstants.REST_USER}/${userId}/samePreviousPasswordUsed`, password); } + + regenerateAccessToken(userId: number, password: string):Promise<AccessTokenRo> { + return this.http.post<AccessTokenRo>(`${SmpConstants.REST_USER}/${userId}/generate-access-token`,password).toPromise() + + } } diff --git a/smp-angular/src/app/user/user-ro.model.ts b/smp-angular/src/app/user/user-ro.model.ts index 1c6b9ac1b3cbc5155c991d1a0435ab3769cfc9f4..118fc0286a1f3819e3d4bc8e52ca9e846d37b159 100644 --- a/smp-angular/src/app/user/user-ro.model.ts +++ b/smp-angular/src/app/user/user-ro.model.ts @@ -5,6 +5,7 @@ export interface UserRo extends SearchTableEntity { username: string; emailAddress: string; password?: string; + accessTokenId?: string; role: string; active: boolean; suspended?: boolean; diff --git a/smp-angular/src/app/user/user.service.ts b/smp-angular/src/app/user/user.service.ts index 4a9a31236d374d2d5e0b33b173babb24191b0604..5e06900c18f995cfca807f8c9cfd2e91c4b3a0e5 100644 --- a/smp-angular/src/app/user/user.service.ts +++ b/smp-angular/src/app/user/user.service.ts @@ -6,6 +6,7 @@ import {SmpConstants} from "../smp.constants"; import {User} from "../security/user.model"; import {AlertService} from "../alert/alert.service"; import {SecurityService} from "../security/security.service"; +import {AccessTokenRo} from "./access-token-ro.model"; @Injectable() export class UserService { @@ -24,4 +25,5 @@ export class UserService { this.alertService.exception('The operation \'update user\' not completed successfully.', err); }); } + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/PropertyInitialization.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/PropertyInitialization.java index f6800427406e030db52d936bd057bbb7434d9efa..33c8b36d47924aad8850c21aad756bfbae2d54c1 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/PropertyInitialization.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/config/PropertyInitialization.java @@ -40,7 +40,6 @@ import java.security.cert.CertificateException; import java.time.LocalDateTime; import java.util.Optional; import java.util.Properties; -import java.util.UUID; import static eu.europa.ec.edelivery.smp.data.ui.enums.SMPPropertyEnum.*; import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INTERNAL_ERROR; @@ -204,7 +203,7 @@ public class PropertyInitialization { }else { // generate new token LOG.info("generate token"); - String trustToken = SecurityUtils.generateStrongPassword(); + String trustToken = SecurityUtils.generateAuthenticationToken(); storeDBEntry(em, SMPPropertyEnum.TRUSTSTORE_PASSWORD_DECRYPTED, trustToken); encTrustEncToken = SecurityUtils.encrypt(fEncryption, trustToken); } @@ -257,7 +256,7 @@ public class PropertyInitialization { Properties fileProperties) { // store keystore password filename - String newKeyPassword = SecurityUtils.generateStrongPassword(); + String newKeyPassword = SecurityUtils.generateAuthenticationToken(); storeDBEntry(em, SMPPropertyEnum.KEYSTORE_PASSWORD_DECRYPTED, newKeyPassword); String encPasswd = SecurityUtils.encrypt(fEncryption, newKeyPassword); storeDBEntry(em, SMPPropertyEnum.KEYSTORE_PASSWORD, encPasswd); 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 51e549974fc63a6f362f8fec45d53e05571c68b6..ba9c5797841b9586e3db72266f27e03917550584 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 @@ -28,6 +28,7 @@ public class DBUserToUserROConverter implements Converter<DBUser, UserRO> { target.setUsername(source.getUsername()); target.setRole(source.getRole()); target.setPassword(source.getPassword()); + target.setAccessTokenId(source.getAccessTokenIdentifier()); target.setPasswordExpired(isPasswordExpired(source)); target.setActive(source.isActive()); target.setId(source.getId()); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java index cd3e1f9eaca385f61cdada9e1962c2f170bde746..db2797e841cd0594bc2962d969be29e4107283d8 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java @@ -79,14 +79,35 @@ public class UserDao extends BaseDao<DBUser> { */ public Optional<DBUser> findUserByIdentifier(String identifier) { - Optional<DBUser> usr = findUserByUsername(identifier); + Optional<DBUser> usr = findUserByAuthenticationToken(identifier); if (!usr.isPresent()){ // try to retrieve by identifier usr = findUserByCertificateId(identifier); } - return usr; } + /** + * Method finds user by user authentication token identifier. If user identity token not exist + * Optional with isPresent - false is returned. + * @param tokeIdentifier + * @return returns Optional DBUser for username + */ + public Optional<DBUser> findUserByAuthenticationToken(String tokeIdentifier) { + // check if blank + if (StringUtils.isBlank(tokeIdentifier)){ + return Optional.empty(); + } + try { + TypedQuery<DBUser> query = memEManager.createNamedQuery("DBUser.getUserByPatId", DBUser.class); + query.setParameter("patId", tokeIdentifier.trim()); + return Optional.of(query.getSingleResult()); + } catch (NoResultException e) { + return Optional.empty(); + } catch (NonUniqueResultException e) { + throw new SMPRuntimeException(ILLEGAL_STATE_USERNAME_MULTIPLE_ENTRY, tokeIdentifier); + } + } + /** * Method finds user by username.If user does not exist * Optional with isPresent - false is returned. diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java index c184ecd70e1add2f754c70ff21e390ba07e0be8b..c3734d5dcd093ef9905e5349f2fde234ff02e2d8 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java @@ -28,6 +28,7 @@ import java.util.Objects; // case insesitive search @NamedQuery(name = "DBUser.getUserByUsernameInsensitive", query = "SELECT u FROM DBUser u WHERE lower(u.username) = lower(:username)"), @NamedQuery(name = "DBUser.getUserByCertificateId", query = "SELECT u FROM DBUser u WHERE u.certificate.certificateId = :certificateId"), + @NamedQuery(name = "DBUser.getUserByPatId", query = "SELECT u FROM DBUser u WHERE u.accessTokenIdentifier = :patId"), @NamedQuery(name = "DBUser.getUserByCertificateIdCaseInsensitive", query = "SELECT u FROM DBUser u WHERE lower(u.certificate.certificateId) = lower(:certificateId)"), }) @NamedNativeQueries({ @@ -57,19 +58,29 @@ public class DBUser extends BaseEntity { @ColumnDescription(comment = "Unique user id") Long id; + @Column(name = "EMAIL", length = CommonColumnsLengths.MAX_PASSWORD_LENGTH) + @ColumnDescription(comment = "User email") + private String emailAddress; + // username @Column(name = "USERNAME", length = CommonColumnsLengths.MAX_USERNAME_LENGTH, unique = true) @ColumnDescription(comment = "Login username") private String username; @Column(name = "PASSWORD", length = CommonColumnsLengths.MAX_PASSWORD_LENGTH) @ColumnDescription(comment = "BCrypted password for username/password login") private String password; - @Column(name = "EMAIL", length = CommonColumnsLengths.MAX_PASSWORD_LENGTH) - @ColumnDescription(comment = "User email") - private String emailAddress; - @Column(name = "PASSWORD_CHANGED") @ColumnDescription(comment = "Last date when password was changed") LocalDateTime passwordChanged; + // Personal access token + @Column(name = "ACCESS_TOKEN_ID", length = CommonColumnsLengths.MAX_USERNAME_LENGTH, unique = true) + @ColumnDescription(comment = "Personal access token id") + private String accessTokenIdentifier; + @Column(name = "ACCESS_TOKEN", length = CommonColumnsLengths.MAX_PASSWORD_LENGTH) + @ColumnDescription(comment = "BCrypted personal access token") + private String accessToken; + @Column(name = "PAT_GENERATED") + @ColumnDescription(comment = "Date when personal access token was generated") + LocalDateTime accessTokenGeneratedOn; @Column(name = "ACTIVE", nullable = false) @ColumnDescription(comment = "Is user active") @@ -124,6 +135,30 @@ public class DBUser extends BaseEntity { this.active = active; } + public String getAccessTokenIdentifier() { + return accessTokenIdentifier; + } + + public void setAccessTokenIdentifier(String accessTokenIdentifier) { + this.accessTokenIdentifier = accessTokenIdentifier; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public LocalDateTime getAccessTokenGeneratedOn() { + return accessTokenGeneratedOn; + } + + public void setAccessTokenGeneratedOn(LocalDateTime accessTokenGeneratedOn) { + this.accessTokenGeneratedOn = accessTokenGeneratedOn; + } + public String getRole() { return role; } @@ -178,7 +213,6 @@ public class DBUser extends BaseEntity { @Override public int hashCode() { - return Objects.hash(super.hashCode(), id, username, certificate); } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/AccessTokenRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/AccessTokenRO.java new file mode 100644 index 0000000000000000000000000000000000000000..ca89868aad6bc73ddaf8243429c3a076c7cea3ab --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/AccessTokenRO.java @@ -0,0 +1,37 @@ +package eu.europa.ec.edelivery.smp.data.ui; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class AccessTokenRO implements Serializable { + + private static final long serialVersionUID = 2821447495333163882L; + + private String identifier; + private String value; + LocalDateTime generatedOn; + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public LocalDateTime getGeneratedOn() { + return generatedOn; + } + + public void setGeneratedOn(LocalDateTime generatedOn) { + this.generatedOn = generatedOn; + } +} \ No newline at end of file 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 fdc754415ae5e1bb8acd9be106b6ca28b0c51c98..77a17abe16bb7094766a828ddbd71375547caec8 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 @@ -18,6 +18,7 @@ public class UserRO extends BaseRO implements UserDetails { private String username; private String password; + private String accessTokenId; private String emailAddress; private Collection<SMPAuthority> authorities; private boolean active = true; @@ -51,6 +52,14 @@ public class UserRO extends BaseRO implements UserDetails { this.password = password; } + public String getAccessTokenId() { + return accessTokenId; + } + + public void setAccessTokenId(String accessTokenId) { + this.accessTokenId = accessTokenId; + } + public String getEmailAddress() { return emailAddress; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/auth/SMPAuthority.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/auth/SMPAuthority.java index ec86348e736cfb21f2f01d9b9a998c0530d1999c..55ea765aaeb0faa2057586c38355f3225674d8a9 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/auth/SMPAuthority.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/auth/SMPAuthority.java @@ -10,6 +10,9 @@ import org.springframework.security.core.GrantedAuthority; public class SMPAuthority implements GrantedAuthority { // static constants for annotations! + public static final String S_AUTHORITY_TOKEN_WS_SMP_ADMIN = "ROLE_WS_SMP_ADMIN"; + public static final String S_AUTHORITY_TOKEN_WS_SERVICE_GROUP_ADMIN = "ROLE_WS_SERVICE_GROUP_ADMIN"; + // ui public static final String S_AUTHORITY_TOKEN_SYSTEM_ADMIN = "ROLE_SYSTEM_ADMIN"; public static final String S_AUTHORITY_TOKEN_SMP_ADMIN = "ROLE_SMP_ADMIN"; public static final String S_AUTHORITY_TOKEN_SERVICE_GROUP_ADMIN = "ROLE_SERVICE_GROUP_ADMIN"; 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 ce93e47bcdd44f4dbe794610bf47526698176460..85ffaa2243d14b04f2166438669a9679643a9583 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 @@ -13,6 +13,7 @@ public enum SMPPropertyEnum { OUTPUT_CONTEXT_PATH("contextPath.output", "true", "This property controls pattern of URLs produced by SMP in GET ServiceGroup responses.", true, false, true, SMPPropertyTypeEnum.BOOLEAN), HTTP_FORWARDED_HEADERS_ENABLED("smp.http.forwarded.headers.enabled", "false", "Use (value true) or remove (value false) forwarded headers! There are security considerations for forwarded headers since an application cannot know if the headers were added by a proxy, as intended, or by a malicious client.", false, false, false, SMPPropertyTypeEnum.BOOLEAN), HTTP_HSTS_MAX_AGE("smp.http.httpStrictTransportSecurity.maxAge", "31536000", "How long(in seconds) HSTS should last in the browser's cache(default one year)", false, false, true, SMPPropertyTypeEnum.INTEGER), + HTTP_HEADER_SEC_POLICY("smp.http.header.security.policy", "default-src 'self'; script-src 'self'; child-src 'none'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; form-action 'self';", "Content Security Policy (CSP)", false, false, true, SMPPropertyTypeEnum.INTEGER), // http proxy configuration HTTP_PROXY_HOST("smp.proxy.host", "", "The http proxy host", false, false, false, SMPPropertyTypeEnum.STRING), HTTP_NO_PROXY_HOSTS("smp.noproxy.hosts", "localhost|127.0.0.1", "list of nor proxy hosts. Ex.: localhost|127.0.0.1", false, false, false, SMPPropertyTypeEnum.STRING), 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 be234e8088e12dc29690dfc624eafffbf401cee2..83bd3547bb73ea2728daa431627df7ebd9f087f3 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 @@ -74,6 +74,10 @@ public class ConfigurationService { return (Integer) configurationDAO.getCachedPropertyValue(HTTP_HSTS_MAX_AGE); } + public String getHttpHeaderContentSecurityPolicy() { + return configurationDAO.getCachedProperty(HTTP_HEADER_SEC_POLICY); + } + public String getHttpProxyHost() { return configurationDAO.getCachedProperty(HTTP_PROXY_HOST); } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java index 5dbba957b85995a9a73d610bf4028b2904f2caae..8a7a792061bc17b1865b11dd9a1384982c3bfcf9 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java @@ -5,16 +5,14 @@ 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.model.DBUserDeleteValidation; -import eu.europa.ec.edelivery.smp.data.ui.CertificateRO; -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.data.ui.*; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; 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.BCryptPasswordHash; +import eu.europa.ec.edelivery.smp.utils.SecurityUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.ConversionService; @@ -80,6 +78,24 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { } + /** + * Method regenerate access token for user and returns access token + * In the database the access token value is saved in format BCryptPasswordHash + * + * @param userRO + * @return generated AccessToken. + */ + @Transactional + public AccessTokenRO generateAccessTokenForUser(Long userId) { + DBUser dbUser = userDao.find(userId); + AccessTokenRO token = SecurityUtils.generateAccessToken(); + dbUser.setAccessTokenIdentifier(token.getIdentifier()); + dbUser.setAccessToken(BCryptPasswordHash.hashPassword(token.getValue())); + dbUser.setAccessTokenGeneratedOn(token.getGeneratedOn()); + userDao.update(dbUser); + return token; + } + @Transactional public void updateUserList(List<UserRO> lst, LocalDateTime passwordChange) { for (UserRO userRO : lst) { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SecurityUtils.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SecurityUtils.java index 561e880e29a0a1d7513b10db1ff05cdb57cad834..7f975c18e099d1bca7efeb694c58fb987277a433 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SecurityUtils.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/utils/SecurityUtils.java @@ -1,5 +1,6 @@ package eu.europa.ec.edelivery.smp.utils; +import eu.europa.ec.edelivery.smp.data.ui.AccessTokenRO; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; @@ -15,6 +16,7 @@ import java.nio.file.Files; import java.security.*; import java.security.cert.Certificate; import java.security.spec.AlgorithmParameterSpec; +import java.time.LocalDateTime; import java.util.Arrays; import java.util.Base64; import java.util.Enumeration; @@ -24,7 +26,9 @@ import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INTERNAL_ERROR; public class SecurityUtils { private static final String VALID_PW_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}[]|:;<>?,./"; + private static final String VALID_USER_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static final int DEFAULT_PASSWORD_LENGTH = 16; + private static final int DEFAULT_USER_LENGTH = 8; public static final String ALGORITHM_KEY = "AES"; public static final String ALGORITHM_ENCRYPTION = "AES/GCM/NoPadding"; @@ -80,8 +84,8 @@ public class SecurityUtils { return newAlias; } - public static String generateStrongPassword(){ - String newKeyPassword = null; + public static String generateAuthenticationToken() { + String newKeyPassword; try { newKeyPassword = RandomStringUtils.random(DEFAULT_PASSWORD_LENGTH, 0, VALID_PW_CHARS.length(), @@ -96,6 +100,29 @@ public class SecurityUtils { return newKeyPassword; } + public static String generateAuthenticationTokenIdentifier() { + String newKeyPassword; + try { + newKeyPassword = RandomStringUtils.random(DEFAULT_USER_LENGTH, 0, VALID_USER_CHARS.length(), + true, false, + VALID_USER_CHARS.toCharArray(), SecureRandom.getInstanceStrong()); + + } catch (NoSuchAlgorithmException e) { + String msg = "Error occurred while generation test password: No strong random algorithm. Error:" + + ExceptionUtils.getRootCauseMessage(e); + throw new SMPRuntimeException(INTERNAL_ERROR, e, msg, e.getMessage()); + } + return newKeyPassword; + } + + public static AccessTokenRO generateAccessToken() { + AccessTokenRO accessToken = new AccessTokenRO(); + accessToken.setGeneratedOn(LocalDateTime.now()); + accessToken.setIdentifier(generateAuthenticationTokenIdentifier()); + accessToken.setValue(generateAuthenticationToken()); + return accessToken; + } + public static void generatePrivateSymmetricKey(File path) { try { @@ -126,9 +153,9 @@ public class SecurityUtils { } public static String encryptWrappedToken(File encKeyFile, String token) { - if (!StringUtils.isBlank(token) && token.startsWith( SecurityUtils.DECRYPTED_TOKEN_PREFIX) ){ + if (!StringUtils.isBlank(token) && token.startsWith(SecurityUtils.DECRYPTED_TOKEN_PREFIX)) { String unWrapToken = getNonEncryptedValue(token); - return SecurityUtils.encrypt(encKeyFile, unWrapToken); + return SecurityUtils.encrypt(encKeyFile, unWrapToken); } return token; } 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 6b83714033e6b8839f5bd0ed4ae79fbb7cab27a9..a3e3e6387b5a0162509eef4ff559e9ada046f1ff 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 @@ -74,7 +74,7 @@ public class TestDBUtils { public static DBUser createDBUser(String username1) { - return createDBUserByUsername(TestConstants.USERNAME_1); + return createDBUserByUsername(username1); } public static DBUser createDBUserByUsername(String userName) { @@ -84,6 +84,8 @@ public class TestDBUtils { dbuser.setEmailAddress("test@test.eu"); dbuser.setPasswordChanged(LocalDateTime.now()); dbuser.setPassword(UUID.randomUUID().toString()); + dbuser.setAccessTokenIdentifier(userName); + dbuser.setAccessToken(UUID.randomUUID().toString()); return dbuser; } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/BCryptPasswordHashTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/BCryptPasswordHashTest.java index 33804fe17721a634daa93d0602d37554a80a72ed..5e11ecf66256d2b8c0c9621a3628ff6a00762e36 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/BCryptPasswordHashTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/BCryptPasswordHashTest.java @@ -13,7 +13,6 @@ package eu.europa.ec.edelivery.smp.utils; -import eu.europa.ec.edelivery.smp.utils.BCryptPasswordHash; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -32,23 +31,21 @@ public class BCryptPasswordHashTest { private static final String PASSWORD = "this_is_sample_password"; private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - private PrintStream initialPrintStream; + private PrintStream initialPrintStream=null; - @Before - public void setUpStreams() { - initialPrintStream = System.out; - System.setOut(new PrintStream(outContent)); - } @After public void cleanUpStreams() { - System.setOut(initialPrintStream); + if (initialPrintStream!=null){ + System.setOut(initialPrintStream); + } } @Test public void generatedHashIsValidTest() { //when String hash = BCryptPasswordHash.hashPassword(PASSWORD); + System.out.println("************: " + BCryptPasswordHash.hashPassword("123456")); //then assertTrue(BCrypt.checkpw(PASSWORD, hash)); @@ -67,6 +64,8 @@ public class BCryptPasswordHashTest { @Test public void mainMethodSupportsMultiplePasswordsAndPrintsThemToStandardOutputTest() { //given + initialPrintStream = System.out; + System.setOut(new PrintStream(outContent)); String[] passwords = new String[]{PASSWORD + 1, PASSWORD + 2, PASSWORD + 3}; //when diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/SecurityUtilsTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/SecurityUtilsTest.java index b566ed466e706b7ec099030b37d60566a5339665..a4e500a893789b3e4f22c04090f90c65e074839c 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/SecurityUtilsTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/utils/SecurityUtilsTest.java @@ -1,6 +1,6 @@ package eu.europa.ec.edelivery.smp.utils; -import eu.europa.ec.edelivery.smp.utils.SecurityUtils; +import eu.europa.ec.edelivery.smp.data.ui.AccessTokenRO; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -49,7 +49,16 @@ public class SecurityUtilsTest { Assert.assertTrue(privateKey instanceof SecretKey); } - + @Test + public void testGenerateAccessToken(){ + // given-when + AccessTokenRO accessToken = SecurityUtils.generateAccessToken(); + // then + assertNotNull(accessToken); + assertNotNull(accessToken.getGeneratedOn()); + assertNotNull(accessToken.getIdentifier()); + assertNotNull(accessToken.getValue()); + } @Test public void encryptDefault() throws IOException { @@ -113,7 +122,6 @@ public class SecurityUtilsTest { public static File generateRandomPrivateKey() throws IOException{ File resource = File.createTempFile( "test-key", ".key"); resource.deleteOnExit(); - SecurityUtils.generatePrivateSymmetricKey(resource); return resource; diff --git a/smp-server-library/src/test/resources/logback-test.xml b/smp-server-library/src/test/resources/logback-test.xml index 8df82e49f56fda7cd57d1787e614f2ed5c4081ea..1abeeedf25fb4f60193e0877d6da2d37c88bf2b4 100644 --- a/smp-server-library/src/test/resources/logback-test.xml +++ b/smp-server-library/src/test/resources/logback-test.xml @@ -17,7 +17,7 @@ </filter> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- rollover daily --> - <fileNamePattern>${log.folder:-logs}/edelivery-smp-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <fileNamePattern>${project.build.directory}/logs/edelivery-smp-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- each file should be at most 30MB, keep 60 days worth of history, but at most 20GB --> <maxFileSize>30MB</maxFileSize> <maxHistory>60</maxHistory> @@ -27,9 +27,6 @@ <pattern>${encoderPattern}</pattern> </encoder> </appender> - - - <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> diff --git a/smp-server-library/src/test/resources/service_integration_test_data.sql b/smp-server-library/src/test/resources/service_integration_test_data.sql index 52032e0b0162609d540701eeeca6e91623e48b3d..f06c8dbf885ddfe33a00ff8dc8231fd4aee5856b 100644 --- a/smp-server-library/src/test/resources/service_integration_test_data.sql +++ b/smp-server-library/src/test/resources/service_integration_test_data.sql @@ -1,4 +1,4 @@ -insert into smp_user(username, password, isadmin) values ('test_admin', '$2a$06$k.Q/6anG4Eq/nNTZ0C1UIuAKxpr6ra5oaMkMSrlESIyA5jKEsUdyS', 1); -insert into smp_user(username, password, isadmin) values ('test_user_hashed_pass', '$2a$06$k.Q/6anG4Eq/nNTZ0C1UIuAKxpr6ra5oaMkMSrlESIyA5jKEsUdyS', 0); -insert into smp_user(username, password, isadmin) values ('test_user_clear_pass', 'gutek123', 0); -insert into smp_user(username, password, isadmin) values ('CN=common name,O=org,C=BE:0000000000000066', '', 0); +insert into smp_user(username, password, ACCESS_TOKEN_ID, ACCESS_TOKEN, isadmin) values ('test_admin','$2a$06$k.Q/6anG4Eq/nNTZ0C1UIuAKxpr6ra5oaMkMSrlESIyA5jKEsUdyS', 'test_pat_admin','$2a$10$bP44Ij/mE6U6OUo/QrKCvOb7ouSClKnyE0Ak6t58BLob9OTI534IO', 1); +insert into smp_user(username, password, ACCESS_TOKEN_ID, ACCESS_TOKEN, isadmin) values ('test_user_hashed_pass','$2a$06$k.Q/6anG4Eq/nNTZ0C1UIuAKxpr6ra5oaMkMSrlESIyA5jKEsUdyS','test_pat_hashed_pass','$2a$10$WftDXn7YqMI/15D8r6fMOOHGQOPxAin8BwQJOjDe1d66SkEuekJ5q', 0); +insert into smp_user(username, password, ACCESS_TOKEN_ID, ACCESS_TOKEN, isadmin) values ('test_user_clear_pass', 'gutek123','test_user_clear_pass', 'gutek123',0); +insert into smp_user(username, password, ACCESS_TOKEN_ID, ACCESS_TOKEN, isadmin) values ('CN=common name,O=org,C=BE:0000000000000066', 'CN=common name,O=org,C=BE:0000000000000066', '',0); diff --git a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql index b6780c75621fb3223c4775421578d5aafabf0914..8a03a034262f28d3e5464b0bc00e869106f5e463 100644 --- a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql +++ b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql @@ -1,12 +1,12 @@ -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'the_admin', '', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test', '', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (6, 'test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (7, 'system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SYSTEM_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (8, 'smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SMP_ADMIN', 1, NOW(), NOW()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (9, 'user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SERVICE_GROUP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu','peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'the_admin', '','the_admin', '', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO','AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi','AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test', '','test', '', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (6, 'test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy','test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (7, 'system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SYSTEM_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (8, 'smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SMP_ADMIN', 1, NOW(), NOW()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (9, 'user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SERVICE_GROUP_ADMIN', 1, NOW(), NOW()); insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (10, 'EHEALTH_SMP_EC', '', 'SERVICE_GROUP_ADMIN', 1, NOW(), NOW()); diff --git a/smp-soapui-tests/groovy/oracle-4.1_integration_test_data.sql b/smp-soapui-tests/groovy/oracle-4.1_integration_test_data.sql index 3b7c9d951550d74884d57ec68ce7a835b598a031..465a0284734abf30168887fc01a2c8f1ee88dae3 100644 --- a/smp-soapui-tests/groovy/oracle-4.1_integration_test_data.sql +++ b/smp-soapui-tests/groovy/oracle-4.1_integration_test_data.sql @@ -25,15 +25,15 @@ DELETE FROM SMP_OWNERSHIP; set define off; -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'the_admin', '', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'test', '', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SYSTEM_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SMP_ADMIN', 1, sysdate, sysdate); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SERVICE_GROUP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu','peppol_user', '$2a$10$.pqNZZ4fRDdNbLhNlnEYg.1/d4yAGpLDgeXpJFI0sw7.WtyKphFzu', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'the_admin', '','the_admin', '', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO','AdminSMP1TEST', '$2a$06$u6Hym7Zrbsf4gEIeAsJRceK.Kg7tei3kDypwucQQdky0lXOLCkrCO', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi','AdminSMP2TEST', '$2a$10$h8Q3Kjbs6ZrGkU6ditjNueINlJOMDJ/g/OKiqFZy32WmdhLjV5TAi', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'test', '','test', '', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy','test1', '$2a$06$toKXJgjqQINZdjQqSao3NeWz2n1S64PFPhVU1e8gIHh4xdbwzy1Uy', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','system', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SYSTEM_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','smp', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SMP_ADMIN', 1, sysdate, sysdate); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36','user', '$2a$06$FDmjewn/do3C219uysNm9.XG8mIn.ubHnMydAzC8lsv61HsRpOR36', 'SERVICE_GROUP_ADMIN', 1, sysdate, sysdate); insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (SMP_USER_SEQ.nextval, 'EHEALTH_SMP_EC', '', 'SERVICE_GROUP_ADMIN', 1, sysdate, sysdate); 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 8b31317dcab1823a802fb479aadfed3e625c81aa..6751b3582d4049468acbb18e5f1595a7b89c00ab 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 @@ -34,12 +34,22 @@ import java.util.*; import static java.util.Locale.US; - +/** + * Authentication provider for the Accounts supporting automated application functionalities. The account are used in SMP for + * webservice access as application to application integration with SMP. Authentication provider supports following + * {@link org.springframework.security.core.Authentication} implementation: + * - {@link org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken} implementation using + * + * + * + * @author Joze Rihtarsic + * @since 4.1 + */ @Import({SmpAppConfig.class}) @Component public class SMPAuthenticationProvider implements AuthenticationProvider { - private static final SMPLogger LOG = SMPLoggerFactory.getLogger(AuthenticationProvider.class); + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPAuthenticationProvider.class); /** * thread safe validator */ @@ -119,7 +129,6 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { } try { - Optional<DBUser> oUsr = mUserDao.findUserByCertificateId(userToken, true); if (!oUsr.isPresent()) { LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_EXISTS, userToken); @@ -182,7 +191,7 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { } } // get role - String role = user.getRole(); + String role = "WS_"+user.getRole(); LOG.securityInfo(SMPMessageCode.SEC_USER_AUTHENTICATED, userToken, role); SMPCertificateAuthentication authentication = new SMPCertificateAuthentication(principal, Collections.singletonList(new SMPAuthority(role)), user); @@ -194,18 +203,15 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { public Authentication authenticateByUsernameToken(UsernamePasswordAuthenticationToken auth) throws AuthenticationException { - // get user - // test credentials - // get and return user roles. - String username = auth.getName(); - String password = auth.getCredentials().toString(); + String authenticationTokenId = auth.getName(); + String authenticationTokenValue = auth.getCredentials().toString(); DBUser user; try { - Optional<DBUser> oUsr = mUserDao.findUserByIdentifier(username); + Optional<DBUser> oUsr = mUserDao.findUserByAuthenticationToken(authenticationTokenId); if (!oUsr.isPresent()) { - LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_EXISTS, username); + LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_EXISTS, authenticationTokenId); //run validation on dummy password to achieve similar response time // as it would be if the password is invalid BCrypt.checkpw(dummyPassword, dummyPasswordHash); @@ -217,27 +223,28 @@ public class SMPAuthenticationProvider implements AuthenticationProvider { user = oUsr.get(); } catch (AuthenticationException ex) { - LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, username, ExceptionUtils.getRootCause(ex), ex); + LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, authenticationTokenId, ExceptionUtils.getRootCause(ex), ex); throw ex; } catch (RuntimeException ex) { - LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, username, ExceptionUtils.getRootCause(ex), ex); + LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, authenticationTokenId, ExceptionUtils.getRootCause(ex), ex); throw new AuthenticationServiceException("Internal server error occurred while user authentication!"); } - String role = user.getRole(); - SMPAuthenticationToken smpAuthenticationToken = new SMPAuthenticationToken(username, password, Collections.singletonList(new SMPAuthority(role)), user); try { - if (!BCrypt.checkpw(password, user.getPassword())) { - LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, username); + if (!BCrypt.checkpw(authenticationTokenValue, user.getAccessToken())) { + LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, authenticationTokenId); throw new BadCredentialsException("Login failed; Invalid userID or password"); } } catch (java.lang.IllegalArgumentException ex) { // password is not hashed; - LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, ex, username); + LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, ex, authenticationTokenId); throw new BadCredentialsException("Login failed; Invalid userID or password"); } - LOG.securityInfo(SMPMessageCode.SEC_USER_AUTHENTICATED, username, role); + String role = "WS_"+user.getRole(); + SMPAuthenticationToken smpAuthenticationToken = new SMPAuthenticationToken(authenticationTokenId, authenticationTokenValue, Collections.singletonList(new SMPAuthority(role)), user); + + LOG.securityInfo(SMPMessageCode.SEC_USER_AUTHENTICATED, authenticationTokenId, role); return smpAuthenticationToken; } 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 new file mode 100644 index 0000000000000000000000000000000000000000..16f1e3e18b4193c9e8bdf92dd2485e38b2a59efb --- /dev/null +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderForUI.java @@ -0,0 +1,124 @@ +package eu.europa.ec.edelivery.smp.auth; + +import eu.europa.ec.edelivery.security.PreAuthenticatedCertificatePrincipal; +import eu.europa.ec.edelivery.security.cert.CertificateValidator; +import eu.europa.ec.edelivery.smp.config.SmpAppConfig; +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.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.logging.SMPMessageCode; +import eu.europa.ec.edelivery.smp.services.CRLVerifierService; +import eu.europa.ec.edelivery.smp.services.ConfigurationService; +import eu.europa.ec.edelivery.smp.services.ui.UITruststoreService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.security.authentication.*; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.bcrypt.BCrypt; +import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; +import org.springframework.stereotype.Component; + +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.CertificateRevokedException; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import static java.util.Locale.US; + +/** + * Authentication provider for the UI authentication. + * + * @author Joze Rihtarsic + * @since 4.2 + */ +@Import({SmpAppConfig.class}) +@Component +public class SMPAuthenticationProviderForUI implements AuthenticationProvider { + + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPAuthenticationProviderForUI.class); + + final UserDao mUserDao; + final CRLVerifierService crlVerifierService; + final UITruststoreService truststoreService; + final ConfigurationService configurationService; + + + @Autowired + public SMPAuthenticationProviderForUI(UserDao mUserDao, CRLVerifierService crlVerifierService, UITruststoreService truststoreService, ConfigurationService configurationService) { + this.mUserDao = mUserDao; + this.crlVerifierService = crlVerifierService; + this.truststoreService = truststoreService; + this.configurationService = configurationService; + } + + @Override + public Authentication authenticate(Authentication authenticationToken) + throws AuthenticationException { + + Authentication authentication = null; + // PreAuthentication token for the rest service certificate authentication + if (authenticationToken instanceof UsernamePasswordAuthenticationToken) { + authentication = authenticateByUsernamePassword((UsernamePasswordAuthenticationToken) authenticationToken); + } + return authentication; + } + + public Authentication authenticateByUsernamePassword(UsernamePasswordAuthenticationToken auth) + throws AuthenticationException { + + String username = auth.getName(); + String userCredentialToken = auth.getCredentials().toString(); + + DBUser user; + try { + Optional<DBUser> oUsr = mUserDao.findUserByUsername(username); + if (!oUsr.isPresent()) { + 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); + throw ex; + + } catch (RuntimeException ex) { + LOG.securityWarn(SMPMessageCode.SEC_USER_NOT_AUTHENTICATED, username, ExceptionUtils.getRootCause(ex), ex); + throw new AuthenticationServiceException("Internal server error occurred while user authentication!"); + + } + String role = user.getRole(); + SMPAuthenticationToken smpAuthenticationToken = new SMPAuthenticationToken(username, userCredentialToken, Collections.singletonList(new SMPAuthority(role)), user); + try { + if (!BCrypt.checkpw(userCredentialToken, user.getPassword())) { + LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, username); + throw new BadCredentialsException("Login failed; Invalid userID or password"); + } + } catch (IllegalArgumentException ex) { + // password is not hashed; + LOG.securityWarn(SMPMessageCode.SEC_INVALID_PASSWORD, ex, username); + throw new BadCredentialsException("Login failed; Invalid userID or password"); + } + LOG.securityInfo(SMPMessageCode.SEC_USER_AUTHENTICATED, username, role); + return smpAuthenticationToken; + } + + @Override + public boolean supports(Class<?> auth) { + LOG.info("Support authentication: " + auth); + boolean supportAuthentication = auth.equals(UsernamePasswordAuthenticationToken.class); + if (!supportAuthentication) { + LOG.warn("SMP does not support authentication type: " + auth); + } + return supportAuthentication; + } +} 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 c8ab53fc8c81a38a9b309ce60b2cf254d668c83b..2079a9b05789548c8ab8b28a918a9b0ddb4005f5 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 @@ -1,5 +1,6 @@ package eu.europa.ec.edelivery.smp.auth; +import eu.europa.ec.edelivery.smp.config.SMPSecurityConstants; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.ui.AuthenticationResource; @@ -19,11 +20,12 @@ public class SMPAuthenticationService { private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPAuthenticationService.class); @Autowired - @Qualifier("smpAuthenticationManager") + @Qualifier(SMPSecurityConstants.SMP_AUTHENTICATION_MANAGER_BEAN) private AuthenticationManager authenticationManager; @Transactional(noRollbackFor = AuthenticationException.class) public Authentication authenticate(String username, String password) { + LOG.debug("Authenticate: [{}]", username); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) authenticationManager.authenticate(token); SecurityContextHolder.getContext().setAuthentication(authentication); 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 a9738babda26eb3e572863d3c0fffa021d26516f..3500fd0aae07726c6e6f9659472cf140b33378bb 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 @@ -39,6 +39,7 @@ public class SMPAuthorizationService { */ public UserRO sanitize(UserRO userRO) { userRO.setPassword(""); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 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/config/GlobalMethodSecurityConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/GlobalMethodSecurityConfig.java index c7bc38d264d8bd69b95b496b45e9bffb165f00ed..cfda72821f6caf57e6332134216f30aefaeccb6b 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/GlobalMethodSecurityConfig.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/GlobalMethodSecurityConfig.java @@ -29,7 +29,7 @@ import org.springframework.security.config.annotation.method.configuration.Globa public class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration { @Autowired - @Qualifier("smpAuthenticationManager") + @Qualifier(SMPSecurityConstants.SMP_AUTHENTICATION_MANAGER_BEAN) private AuthenticationManager am; @Override diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java index 6202bb127bb0f8c0e546f5157210e5e92eb39ca6..3618c140fa093570b93fc989384d518ba349669e 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java @@ -16,11 +16,13 @@ package eu.europa.ec.edelivery.smp.config; import eu.europa.ec.edelivery.security.ClientCertAuthenticationFilter; import eu.europa.ec.edelivery.security.EDeliveryX509AuthenticationFilter; import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationProvider; +import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationProviderForUI; import eu.europa.ec.edelivery.smp.auth.URLCsrfMatcher; import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority; import eu.europa.ec.edelivery.smp.error.SpringSecurityExceptionHandler; import eu.europa.ec.edelivery.smp.services.ConfigurationService; import eu.europa.ec.edelivery.smp.utils.SMPCookieWriter; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -66,11 +68,15 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { private static final Logger LOG = LoggerFactory.getLogger(SpringSecurityConfig.class); SMPAuthenticationProvider smpAuthenticationProvider; + SMPAuthenticationProviderForUI smpAuthenticationProviderForUI; CasAuthenticationProvider casAuthenticationProvider; - ClientCertAuthenticationFilter ClientCertAuthenticationFilter; + // Accounts supporting automated application functionalities + ClientCertAuthenticationFilter clientCertAuthenticationFilter; EDeliveryX509AuthenticationFilter x509AuthenticationFilter; + // User account CasAuthenticationFilter casAuthenticationFilter; CasAuthenticationEntryPoint casAuthenticationEntryPoint; + CsrfTokenRepository csrfTokenRepository; HttpFirewall httpFirewall; RequestMatcher csrfURLMatcher; @@ -85,13 +91,14 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { * Initialize beans. Use lazy initialization for filter to avoid circular dependencies * * @param smpAuthenticationProvider - * @param ClientCertAuthenticationFilter + * @param clientCertAuthenticationFilter * @param x509AuthenticationFilter */ @Autowired public SpringSecurityConfig(SMPAuthenticationProvider smpAuthenticationProvider, + SMPAuthenticationProviderForUI smpAuthenticationProviderForUI, ConfigurationService configurationService, - @Lazy ClientCertAuthenticationFilter ClientCertAuthenticationFilter, + @Lazy ClientCertAuthenticationFilter clientCertAuthenticationFilter, @Lazy EDeliveryX509AuthenticationFilter x509AuthenticationFilter, @Lazy CsrfTokenRepository csrfTokenRepository, @Lazy RequestMatcher csrfURLMatcher, @@ -104,8 +111,9 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { super(false); this.configurationService = configurationService; this.smpAuthenticationProvider = smpAuthenticationProvider; + this.smpAuthenticationProviderForUI = smpAuthenticationProviderForUI; this.casAuthenticationProvider = casAuthenticationProvider; - this.ClientCertAuthenticationFilter = ClientCertAuthenticationFilter; + this.clientCertAuthenticationFilter = clientCertAuthenticationFilter; this.x509AuthenticationFilter = x509AuthenticationFilter; this.casAuthenticationFilter = casAuthenticationFilter; this.casAuthenticationEntryPoint = casAuthenticationEntryPoint; @@ -116,15 +124,8 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { - httpSecurity - .csrf().csrfTokenRepository(csrfTokenRepository).requireCsrfProtectionMatcher(csrfURLMatcher).and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) - //on authentication, a new HTTP Session is created, the old one is invalidated and the attributes from the old session are copied over. - .sessionFixation().migrateSession() - //In order to force only one concurrent sessions for the same user, - .maximumSessions(1).and() - .and(); + + configureSecurityHeaders(httpSecurity); ExceptionHandlingConfigurer<HttpSecurity> exceptionHandlingConfigurer = httpSecurity.exceptionHandling(); if (configurationService.isSSOEnabledForUserAuthentication()) { @@ -132,7 +133,6 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { exceptionHandlingConfigurer = exceptionHandlingConfigurer.defaultAuthenticationEntryPointFor(casAuthenticationEntryPoint, new AntPathRequestMatcher(SMP_SECURITY_PATH_CAS_AUTHENTICATE)); } exceptionHandlingConfigurer.authenticationEntryPoint(new SpringSecurityExceptionHandler()); - httpSecurity = exceptionHandlingConfigurer .accessDeniedHandler(new SpringSecurityExceptionHandler()) .and() @@ -145,29 +145,9 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { LOG.debug("The CAS authentication is enabled. Add CAS filter!"); httpSecurity = httpSecurity.addFilter(casAuthenticationFilter); } - // set HstsMAxAge - Integer maxAge = configurationService.getHttpHeaderHstsMaxAge(); - if (maxAge == null || maxAge < 0) { - LOG.info("The httpStrictTransportSecurity (HSTS) policy is set for HTTPS/1Y!"); - httpSecurity = httpSecurity.headers() - .httpStrictTransportSecurity() - .includeSubDomains(true) - .preload(false) - .maxAgeInSeconds(31536000).and().and(); - } else if (maxAge == 0) { - LOG.warn("The httpStrictTransportSecurity (HSTS) policy is disabled!"); - httpSecurity = httpSecurity.headers().httpStrictTransportSecurity().disable().and(); - } else { - LOG.info("The httpStrictTransportSecurity (HSTS) policy is set to [{}] for http and https!", maxAge); - httpSecurity = httpSecurity.headers() - .httpStrictTransportSecurity() - .includeSubDomains(true) - .preload(false) - .maxAgeInSeconds(maxAge) - .requestMatcher(AnyRequestMatcher.INSTANCE).and().and(); - } - httpSecurity.addFilter(ClientCertAuthenticationFilter) + + httpSecurity.addFilter(clientCertAuthenticationFilter) .addFilter(x509AuthenticationFilter) .httpBasic().authenticationEntryPoint(new SpringSecurityExceptionHandler()).and() // username .anonymous().authorities(SMPAuthority.S_AUTHORITY_ANONYMOUS.getAuthority()).and() @@ -178,10 +158,14 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { .and() .authorizeRequests() .antMatchers(HttpMethod.DELETE).hasAnyAuthority( + SMPAuthority.S_AUTHORITY_TOKEN_WS_SERVICE_GROUP_ADMIN, + SMPAuthority.S_AUTHORITY_TOKEN_WS_SMP_ADMIN, SMPAuthority.S_AUTHORITY_SMP_ADMIN.getAuthority(), SMPAuthority.S_AUTHORITY_SERVICE_GROUP.getAuthority(), SMPAuthority.S_AUTHORITY_SYSTEM_ADMIN.getAuthority()) .antMatchers(HttpMethod.PUT).hasAnyAuthority( + SMPAuthority.S_AUTHORITY_TOKEN_WS_SERVICE_GROUP_ADMIN, + SMPAuthority.S_AUTHORITY_TOKEN_WS_SMP_ADMIN, SMPAuthority.S_AUTHORITY_SMP_ADMIN.getAuthority(), SMPAuthority.S_AUTHORITY_SERVICE_GROUP.getAuthority(), SMPAuthority.S_AUTHORITY_SYSTEM_ADMIN.getAuthority()) @@ -194,6 +178,46 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { ; } + protected void configureSecurityHeaders(HttpSecurity httpSecurity) throws Exception { + // configure session and csrf headers + httpSecurity + .csrf().csrfTokenRepository(csrfTokenRepository).requireCsrfProtectionMatcher(csrfURLMatcher).and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) + //on authentication, a new HTTP Session is created, the old one is invalidated and the attributes from the old session are copied over. + .sessionFixation().migrateSession() + //In order to force only one concurrent sessions for the same user, + .maximumSessions(1).and() + .and(); + + // set HstsMAxAge + Integer maxAge = configurationService.getHttpHeaderHstsMaxAge(); + if (maxAge == null || maxAge < 0) { + LOG.info("The httpStrictTransportSecurity (HSTS) policy is set for HTTPS/1Y!"); + httpSecurity = httpSecurity.headers() + .httpStrictTransportSecurity() + .includeSubDomains(true) + .preload(false) + .maxAgeInSeconds(31536000).and().and(); + } else if (maxAge == 0) { + LOG.warn("The httpStrictTransportSecurity (HSTS) policy is disabled!"); + httpSecurity = httpSecurity.headers().httpStrictTransportSecurity().disable().and(); + } else { + LOG.info("The httpStrictTransportSecurity (HSTS) policy is set to [{}] for http and https!", maxAge); + httpSecurity = httpSecurity.headers() + .httpStrictTransportSecurity() + .includeSubDomains(true) + .preload(false) + .maxAgeInSeconds(maxAge) + .requestMatcher(AnyRequestMatcher.INSTANCE).and().and(); + } + + String contentSecurityPolicy = configurationService.getHttpHeaderContentSecurityPolicy(); + if (StringUtils.isNotBlank(contentSecurityPolicy)) { + httpSecurity = httpSecurity.headers().contentSecurityPolicy(contentSecurityPolicy).and().and(); + } + } + @Override public void configure(WebSecurity web) throws Exception { super.configure(web); @@ -207,7 +231,12 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { LOG.info("[CAS] Authentication Provider enabled"); auth.authenticationProvider(casAuthenticationProvider); } + // add UI authentication provider + auth.authenticationProvider(smpAuthenticationProviderForUI); + // fallback automation user token authentication auth.authenticationProvider(smpAuthenticationProvider); + + } @Override diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java index a7265a7064044b57bc1b018678188479532dcb28..8ba71f1a4c9bff5b581634a57cae58b5cc8867e2 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java @@ -40,6 +40,7 @@ import java.util.List; import static eu.europa.ec.edelivery.smp.controllers.WebConstans.HTTP_PARAM_DOMAIN; import static eu.europa.ec.edelivery.smp.controllers.WebConstans.HTTP_PARAM_OWNER; +import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.*; import static eu.europa.ec.smp.api.Identifiers.asParticipantId; import static org.springframework.http.ResponseEntity.created; import static org.springframework.http.ResponseEntity.ok; @@ -83,7 +84,7 @@ public class ServiceGroupController { @PutMapping - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) + @Secured({S_AUTHORITY_TOKEN_SYSTEM_ADMIN, S_AUTHORITY_TOKEN_SMP_ADMIN, S_AUTHORITY_TOKEN_WS_SMP_ADMIN }) public ResponseEntity saveServiceGroup(HttpServletRequest httpReq, @PathVariable String serviceGroupId, @RequestHeader(name = HTTP_PARAM_OWNER, required = false) String serviceGroupOwner, @@ -107,7 +108,7 @@ public class ServiceGroupController { } @DeleteMapping - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) + @Secured({S_AUTHORITY_TOKEN_SYSTEM_ADMIN, S_AUTHORITY_TOKEN_SMP_ADMIN, S_AUTHORITY_TOKEN_WS_SMP_ADMIN }) public ResponseEntity deleteServiceGroup(HttpServletRequest httpReq, @PathVariable String serviceGroupId) { String authentUser = SecurityContextHolder.getContext().getAuthentication().getName(); String host = getRemoteHost(httpReq); diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceMetadataController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceMetadataController.java index f59d525d83e37302feda6968ae1d0c89e17ad8c7..ce0b0da9df0eac7a9f3cc598e45fd7031a120799 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceMetadataController.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceMetadataController.java @@ -72,8 +72,10 @@ public class ServiceMetadataController { } @PutMapping - @PreAuthorize("hasAnyAuthority(T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_SMP_ADMIN) OR" + - " @serviceGroupService.isServiceGroupOwner(authentication.name, #serviceGroupId)") + /// @PreAuthorize("hasAnyAuthority(T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_SMP_ADMIN) OR @serviceGroupService.isServiceGroupOwner(authentication.name, #serviceGroupId)") + @PreAuthorize("hasAnyAuthority(T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_SMP_ADMIN, " + + " T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_WS_SMP_ADMIN) " + + " OR @serviceGroupService.isServiceGroupOwner(authentication.name, #serviceGroupId)") public ResponseEntity saveServiceMetadata(HttpServletRequest httpReq, @PathVariable String serviceGroupId, @PathVariable String serviceMetadataId, @@ -94,8 +96,9 @@ public class ServiceMetadataController { } @DeleteMapping - @PreAuthorize("hasAnyAuthority(T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_SMP_ADMIN) OR" + - " @serviceGroupService.isServiceGroupOwner(authentication.name, #serviceGroupId)") + @PreAuthorize("hasAnyAuthority(T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_SMP_ADMIN, " + + " T(eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority).S_AUTHORITY_TOKEN_WS_SMP_ADMIN) " + + " OR @serviceGroupService.isServiceGroupOwner(authentication.name, #serviceGroupId)") public ResponseEntity deleteServiceMetadata(HttpServletRequest httpReq, @PathVariable String serviceGroupId, @PathVariable String serviceMetadataId, diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java index 072c89bbd98383043b07ed2345bd6869887f6c08..81ef1f164ba8764d08baad89d0218af3518978d8 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java @@ -60,7 +60,7 @@ public class MonitorResource { @RequestMapping(method = RequestMethod.GET, path = "/is-alive") - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN,SMPAuthority.S_AUTHORITY_TOKEN_WS_SMP_ADMIN}) public ResponseEntity isAlive() { String user = SecurityContextHolder.getContext().getAuthentication().getName(); diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java index 3b151949e40f7db6021697d6d49fd3f8542af805..8040dd2d3a87f77f658eba17020a7d41a5611535 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java @@ -1,13 +1,10 @@ package eu.europa.ec.edelivery.smp.ui; import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationToken; +import eu.europa.ec.edelivery.smp.data.ui.*; import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority; 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.CertificateRO; -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.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UITruststoreService; @@ -99,8 +96,6 @@ public class UserResource { @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#id)") public CertificateRO uploadCertificate(@PathVariable("id") Long id, @RequestBody byte[] data) { LOG.info("Got certificate data size: {}", data.length); - - try { return uiTruststoreService.getCertificateData(data, true); } catch (IOException | CertificateException e) { @@ -109,6 +104,15 @@ public class UserResource { return null; } + @PostMapping(value = "/{userId}/generate-access-token" ,produces = {"application/json"}) + @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#userId)") + public AccessTokenRO generateAccessToken(@PathVariable("userId") Long userId,@RequestBody String password) { + AccessTokenRO accessToken = uiUserService.generateAccessTokenForUser(userId); + LOG.debug("Access token generated [{}]", accessToken.getIdentifier()); + accessToken.setGeneratedOn(null); + return accessToken; + } + @PostMapping(path = "/{id}/samePreviousPasswordUsed", produces = {"application/json"}) @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#id)") public boolean samePreviousPasswordUsed(@PathVariable("id") Long id, @RequestBody String password) { diff --git a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl index 70e5454ba9aee559117c6f3a09de6dfdccb020aa..714e760f9b473eb63a83ab111326ffd015503de1 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl @@ -232,6 +232,9 @@ create table SMP_USER ( ID bigint not null comment 'Unique user id', + ACCESS_TOKEN varchar(256) CHARACTER SET utf8 COLLATE utf8_bin comment 'BCrypted personal access token', + PAT_GENERATED datetime comment 'Date when personal access token was generated', + ACCESS_TOKEN_ID varchar(256) CHARACTER SET utf8 COLLATE utf8_bin comment 'Personal access token id', ACTIVE bit not null comment 'Is user active', CREATED_ON datetime not null, EMAIL varchar(256) CHARACTER SET utf8 COLLATE utf8_bin comment 'User email', @@ -247,6 +250,9 @@ ID bigint not null, REV bigint not null, REVTYPE tinyint, + ACCESS_TOKEN varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, + PAT_GENERATED datetime, + ACCESS_TOKEN_ID varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, ACTIVE bit, CREATED_ON datetime, EMAIL varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, @@ -283,6 +289,9 @@ create index SMP_SMD_DOC_SCH_IDX on SMP_SERVICE_METADATA (DOCUMENT_SCHEME); alter table SMP_SERVICE_METADATA add constraint SMP_MT_UNIQ_SG_DOC_IDX unique (FK_SG_DOM_ID, DOCUMENT_IDENTIFIER, DOCUMENT_SCHEME); + alter table SMP_USER + add constraint UK_tk9bjsmd2mevgt3b997i6pl27 unique (ACCESS_TOKEN_ID); + alter table SMP_USER add constraint UK_rt1f0anklfo05lt0my05fqq6 unique (USERNAME); diff --git a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl index 5233dc83ee6ac832f28d67effd32059723da2809..bc1fad113181797ff2f63ddfe6e0d0e3e2916b80 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl @@ -313,6 +313,9 @@ create sequence SMP_USER_SEQ start with 1 increment by 1; create table SMP_USER ( ID number(19,0) not null, + ACCESS_TOKEN varchar2(256 char), + PAT_GENERATED timestamp, + ACCESS_TOKEN_ID varchar2(256 char), ACTIVE number(1,0) not null, CREATED_ON timestamp not null, EMAIL varchar2(256 char), @@ -330,6 +333,15 @@ create sequence SMP_USER_SEQ start with 1 increment by 1; comment on column SMP_USER.ID is 'Unique user id'; + comment on column SMP_USER.ACCESS_TOKEN is + 'BCrypted personal access token'; + + comment on column SMP_USER.PAT_GENERATED is + 'Date when personal access token was generated'; + + comment on column SMP_USER.ACCESS_TOKEN_ID is + 'Personal access token id'; + comment on column SMP_USER.ACTIVE is 'Is user active'; @@ -352,6 +364,9 @@ create sequence SMP_USER_SEQ start with 1 increment by 1; ID number(19,0) not null, REV number(19,0) not null, REVTYPE number(3,0), + ACCESS_TOKEN varchar2(256 char), + PAT_GENERATED timestamp, + ACCESS_TOKEN_ID varchar2(256 char), ACTIVE number(1,0), CREATED_ON timestamp, EMAIL varchar2(256 char), @@ -382,6 +397,9 @@ create index SMP_SMD_DOC_SCH_IDX on SMP_SERVICE_METADATA (DOCUMENT_SCHEME); alter table SMP_SERVICE_METADATA add constraint SMP_MT_UNIQ_SG_DOC_IDX unique (FK_SG_DOM_ID, DOCUMENT_IDENTIFIER, DOCUMENT_SCHEME); + alter table SMP_USER + add constraint UK_tk9bjsmd2mevgt3b997i6pl27 unique (ACCESS_TOKEN_ID); + alter table SMP_USER add constraint UK_rt1f0anklfo05lt0my05fqq6 unique (USERNAME); diff --git a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java index c334114c27fd5c2e52bc86aa2acbb696f6966533..4a279b284c7703ead6211b932adc2fb445822cb0 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java @@ -55,9 +55,9 @@ public class SecurityConfigurationTest { public static final String RETURN_LOGGED_USER_PATH = "/getLoggedUsername"; - public static final String TEST_USERNAME_DB_CLEAR_PASS = "test_user_clear_pass"; - public static final String TEST_USERNAME_DB_HASHED_PASS = "test_user_hashed_pass"; - public static final String PASSWORD = "test123"; + public static final String TEST_USERNAME_DB_CLEAR_PASS = "test_pat_clear_pass"; + public static final String TEST_USERNAME_DB_HASHED_PASS = "test_pat_hashed_pass"; + public static final String PASSWORD = "123456"; public static final String BLUE_COAT_VALID_HEADER = "sno=bb66&subject=C=BE,O=org,CN=common name&validfrom=Dec 6 17:41:42 2016 GMT&validto=Jul 9 23:59:00 2050 GMT&issuer=C=x,O=y,CN=z"; public static final String BLUE_COAT_VALID_HEADER_UPPER_SN = "sno=BB66&subject=C=BE,O=org,CN=common name&validfrom=Dec 6 17:41:42 2016 GMT&validto=Jul 9 23:59:00 2050 GMT&issuer=C=x,O=y,CN=z"; public static final String TEST_USERNAME_BLUE_COAT = "CN=common name,O=org,C=BE:000000000000bb66"; @@ -112,7 +112,7 @@ public class SecurityConfigurationTest { } @Test - public void userStoredWithUpperCaseUsernameIsAuthorizedForPutTest() throws Exception { + public void userStoredWithUpperCaseUsernameIsAuthorizedForPutTestIdCaseSensitive() throws Exception { String upperCaseUsername = TEST_USERNAME_DB_HASHED_PASS.toUpperCase(); // test that is not the same Assert.assertNotEquals(upperCaseUsername, TEST_USERNAME_DB_HASHED_PASS); @@ -120,13 +120,9 @@ public class SecurityConfigurationTest { mvc.perform(MockMvcRequestBuilders.put(RETURN_LOGGED_USER_PATH) .with(httpBasic(upperCaseUsername, PASSWORD)) .with(csrf())) - .andExpect(status().isOk()) - .andExpect(content().string(upperCaseUsername)); + .andExpect(status().isUnauthorized()); } - - - @Test public void userStoredWithClearPassIsNotAuthorizedForPutTest() throws Exception { mvc.perform(MockMvcRequestBuilders.put(RETURN_LOGGED_USER_PATH) diff --git a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java index e303910822884303c73098badb4cc95b8fe4cd38..a58ef9a104252daa5b42303b7df4b2c63d9600d4 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java @@ -88,7 +88,7 @@ public class SignatureValidatorTest { private static final String C14N_METHOD = CanonicalizationMethod.INCLUSIVE; private static final String PARSER_DISALLOW_DTD_PARSING_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); @Autowired private WebApplicationContext webAppContext; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderTest.java index 95f7134a08df749ad4f59682506f95a4d8f07b00..f2a84f1e8ba988b4395ac66c2412fdb75dc81453 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProviderTest.java @@ -35,12 +35,10 @@ public class SMPAuthenticationProviderTest { UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken("User", "User"); DBUser user = new DBUser(); user.setId(1L); - - user.setUsername("User"); - user.setPassword(BCrypt.hashpw("InvalidPassword", BCrypt.gensalt())); + user.setAccessTokenIdentifier("User"); + user.setAccessToken(BCrypt.hashpw("InvalidPassword", BCrypt.gensalt())); user.setRole("MY_ROLE"); - doReturn(Optional.of(user)).when(mockUserDao).findUserByIdentifier(any()); int count = 100; long averageExists = 0; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerSingleDomainTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerSingleDomainTest.java index f868c8f8ce5b5002dba3c3c88e3cfa86f32e7fc0..592ad8bb22ee8e38ea145b4d354594562c58d552 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerSingleDomainTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerSingleDomainTest.java @@ -84,7 +84,7 @@ public class ServiceGroupControllerSingleDomainTest { private static final String OTHER_OWNER_NAME = "CN=EHEALTH_SMP_TEST_BRAZIL,O=European Commission,C=BE:48b681ee8e0dcc08"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "test123"); @Autowired private WebApplicationContext webAppContext; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java index d209d49cd2841c7ef047c7099f75c710e038aedc..67b1cf3b324056d0751b50002e02f341da0ed8b4 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java @@ -85,7 +85,7 @@ public class ServiceGroupControllerTest { private static final String OTHER_OWNER_NAME_URL_ENCODED = "CN=utf-8_%C5%BC_SMP,O=EC,C=BE:0000000000000666"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); @Autowired private WebApplicationContext webAppContext; diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java index 2d66e8cef5aba2d183030fa062c80dd940e99a7b..6360cbfd1bbc3d9309d212a73c9ef3b234c44d0c 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java @@ -56,7 +56,7 @@ public class MonitorResourceTest { public ExpectedException expectedEx = ExpectedException.none(); private static final String URL = "/monitor/is-alive"; - private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("smp_admin", "test123"); + private static final RequestPostProcessor ADMIN_CREDENTIALS = httpBasic("pat_smp_admin", "123456"); @Autowired private WebApplicationContext webAppContext; diff --git a/smp-webapp/src/test/resources/logback-test.xml b/smp-webapp/src/test/resources/logback-test.xml index 8df82e49f56fda7cd57d1787e614f2ed5c4081ea..14096e01d343057269fd34ce2fc0ee1d7459e49f 100644 --- a/smp-webapp/src/test/resources/logback-test.xml +++ b/smp-webapp/src/test/resources/logback-test.xml @@ -17,7 +17,7 @@ </filter> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- rollover daily --> - <fileNamePattern>${log.folder:-logs}/edelivery-smp-%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <fileNamePattern>${project.build.directory}/logs/edelivery-smp-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- each file should be at most 30MB, keep 60 days worth of history, but at most 20GB --> <maxFileSize>30MB</maxFileSize> <maxHistory>60</maxHistory> @@ -28,8 +28,6 @@ </encoder> </appender> - - <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> diff --git a/smp-webapp/src/test/resources/webapp_integration_test_data.sql b/smp-webapp/src/test/resources/webapp_integration_test_data.sql index f56a4131c41bc825c299e0e548c3f1cadd9c730a..e98695f944b8cd1eb3ef3b8e3850e33c89d500b4 100644 --- a/smp-webapp/src/test/resources/webapp_integration_test_data.sql +++ b/smp-webapp/src/test/resources/webapp_integration_test_data.sql @@ -25,12 +25,11 @@ insert into SMP_CONFIGURATION (PROPERTY, VALUE, CREATED_ON, LAST_UPDATED_ON) VAL insert into SMP_CONFIGURATION (PROPERTY, VALUE, CREATED_ON, LAST_UPDATED_ON) VALUES ('smp.http.forwarded.headers.enabled', 'true',CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'smp_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'sg_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'sys_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SYSTEM_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); - -insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'test_user_hashed_pass', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test_user_clear_pass', 'test123', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'smp_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW','pat_smp_admin', '$2a$10$bP44Ij/mE6U6OUo/QrKCvOb7ouSClKnyE0Ak6t58BLob9OTI534IO', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'sg_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'pat_sg_admin', '$2a$10$bP44Ij/mE6U6OUo/QrKCvOb7ouSClKnyE0Ak6t58BLob9OTI534IO', 'SERVICE_GROUP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'sys_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'pat_sys_admin', '$2a$10$bP44Ij/mE6U6OUo/QrKCvOb7ouSClKnyE0Ak6t58BLob9OTI534IO', 'SYSTEM_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER(ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'test_user_hashed_pass','$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'test_pat_hashed_pass','$2a$10$bP44Ij/mE6U6OUo/QrKCvOb7ouSClKnyE0Ak6t58BLob9OTI534IO', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER(ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test_user_clear_pass', 'test123', 'test_pat_clear_pass', 'test123','SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (6, 'cert1', '', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_CERTIFICATE (ID, CERTIFICATE_ID, VALID_FROM, VALID_TO, CREATED_ON, LAST_UPDATED_ON) values (6, 'CN=common name,O=org,C=BE:000000000000bb66', null,null,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); diff --git a/smp-webapp/src/test/resources/webapp_integration_test_data_one_domain.sql b/smp-webapp/src/test/resources/webapp_integration_test_data_one_domain.sql index ca85e5c2b5eb158fa94d0ceb74685e40def18544..17ef0dfa58f890fe4ad4dc1287f9c9a2c8393ac6 100644 --- a/smp-webapp/src/test/resources/webapp_integration_test_data_one_domain.sql +++ b/smp-webapp/src/test/resources/webapp_integration_test_data_one_domain.sql @@ -15,12 +15,12 @@ insert into SMP_CONFIGURATION (PROPERTY, VALUE, CREATED_ON, LAST_UPDATED_ON) VAL insert into SMP_CONFIGURATION (PROPERTY, VALUE, CREATED_ON, LAST_UPDATED_ON) VALUES ('contextPath.output', 'true',CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'smp_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'sg_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER (ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'sys_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SYSTEM_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (1, 'smp_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW','pat_smp_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (2, 'sg_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'pat_sg_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER (ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (3, 'sys_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW','pat_sys_admin', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SYSTEM_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'test_user_hashed_pass', '$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); -insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test_user_clear_pass', 'test123', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER(ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (4, 'test_user_hashed_pass','$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'test_pat_hashed_pass','$2a$06$AXSSUDJlpzzq/gPZb7eIBeb8Mi0.PTKqDjzujZH.bWPwj5.ePEInW', 'SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_USER(ID, USERNAME, PASSWORD, ACCESS_TOKEN_ID, ACCESS_TOKEN, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (5, 'test_user_clear_pass','test123','test_pat_clear_pass','test123','SERVICE_GROUP_ADMIN',1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_USER(ID, USERNAME, PASSWORD, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) values (6, 'cert1', '', 'SMP_ADMIN', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_CERTIFICATE (ID, CERTIFICATE_ID, VALID_FROM, VALID_TO, CREATED_ON, LAST_UPDATED_ON) values (6, 'CN=common name,O=org,C=BE:0000000000000066', null,null,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());