From 369a850361277ab7e666986b88809a7c28e13853 Mon Sep 17 00:00:00 2001 From: Joze RIHTARSIC <joze.RIHTARSIC@ext.ec.europa.eu> Date: Fri, 10 Jun 2022 10:59:11 +0200 Subject: [PATCH] Small ui fixes --- smp-angular/src/app/alert/alert.component.ts | 24 +++++-- .../src/app/domain/domain.component.ts | 29 +++++++-- .../keystore-edit-dialog.component.ts | 7 +- .../keystore-import-dialog.component.ts | 64 +------------------ .../src/app/property/property.component.ts | 23 +++++-- .../service-group-edit.component.ts | 22 +++++-- ...ervice-metadata-wizard-dialog.component.ts | 2 +- .../service-group-search.component.ts | 25 ++++++-- .../truststore-edit-dialog.component.ts | 24 +++++-- .../user-details-dialog.component.ts | 2 +- smp-angular/src/app/user/user.component.ts | 25 ++++++-- smp-angular/src/app/user/user.service.ts | 6 +- .../spi/ExamplePayloadValidatorSpiImpl.java | 7 ++ .../smp/data/ui/enums/SMPPropertyEnum.java | 4 +- .../edelivery/smp/exceptions/ErrorCode.java | 10 +-- .../smp/services/CRLVerifierService.java | 8 +-- .../smp/services/PayloadValidatorService.java | 6 +- .../smp/services/ui/UITruststoreService.java | 19 ++++-- .../smp/services/CRLVerifierServiceTest.java | 6 +- .../services/PayloadValidatorServiceTest.java | 4 +- .../ui/UIUserServiceIntegrationTest.java | 4 +- smp-webapp/src/main/resources/logback.xml | 5 -- smp-webapp/src/main/smp-setup/logback.xml | 6 -- 23 files changed, 193 insertions(+), 139 deletions(-) diff --git a/smp-angular/src/app/alert/alert.component.ts b/smp-angular/src/app/alert/alert.component.ts index 120e2ea32..d1f58000c 100644 --- a/smp-angular/src/app/alert/alert.component.ts +++ b/smp-angular/src/app/alert/alert.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog} from '@angular/material/dialog'; @@ -17,7 +25,7 @@ import {ObjectPropertiesDialogComponent} from "../common/dialogs/object-properti templateUrl: './alert.component.html', styleUrls: ['./alert.component.css'] }) -export class AlertComponent implements OnInit, AfterViewInit { +export class AlertComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>; @ViewChild('rowActions') rowActions: TemplateRef<any>; @@ -42,12 +50,19 @@ export class AlertComponent implements OnInit, AfterViewInit { protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertMessageService, - public dialog: MatDialog) { + public dialog: MatDialog, + private changeDetector: ChangeDetectorRef) { } ngOnInit() { this.alertController = new AlertController(this.http, this.lookups, this.dialog); + } + + ngAfterViewChecked() { + this.changeDetector.detectChanges(); + } + initColumns() { this.columnPicker.allColumns = [ { name: 'Alert date', @@ -105,10 +120,11 @@ export class AlertComponent implements OnInit, AfterViewInit { }, ]; this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially); + this.searchTable.tableColumnInit(); } ngAfterViewInit() { - this.searchTable.tableColumnInit(); + this.initColumns(); } diff --git a/smp-angular/src/app/domain/domain.component.ts b/smp-angular/src/app/domain/domain.component.ts index 6644f8316..8b4e34f99 100644 --- a/smp-angular/src/app/domain/domain.component.ts +++ b/smp-angular/src/app/domain/domain.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog, MatDialogRef} from '@angular/material/dialog'; @@ -22,7 +30,7 @@ import {SMLResult} from "./sml-result.model"; templateUrl: './domain.component.html', styleUrls: ['./domain.component.css'] }) -export class DomainComponent implements OnInit, AfterViewInit { +export class DomainComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>; @ViewChild('certificateAliasTemplate') certificateAliasColumn: TemplateRef<any>; @@ -42,7 +50,8 @@ export class DomainComponent implements OnInit, AfterViewInit { protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertMessageService, - public dialog: MatDialog) { + public dialog: MatDialog, + private changeDetector: ChangeDetectorRef) { // check application settings @@ -51,7 +60,9 @@ export class DomainComponent implements OnInit, AfterViewInit { ngOnInit() { this.domainController = new DomainController(this.http, this.lookups, this.dialog); + } + initColumns() { this.columnPicker.allColumns = [ { name: 'Domain code', @@ -76,7 +87,6 @@ export class DomainComponent implements OnInit, AfterViewInit { cellTemplate: this.certificateAliasColumn, width: 150 }, - { name: 'SML SMP Id', title: "SMP identifier for SML integration", @@ -104,11 +114,15 @@ export class DomainComponent implements OnInit, AfterViewInit { width: 130 }, ]; - this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially); + this.searchTable.tableColumnInit(); + } + + ngAfterViewChecked() { + this.changeDetector.detectChanges(); } ngAfterViewInit() { - this.searchTable.tableColumnInit(); + this.initColumns(); // if system admin refresh certificate list! if (this.securityService.isCurrentUserSystemAdmin()) { this.lookups.refreshCertificateLookup(); @@ -169,7 +183,8 @@ export class DomainComponent implements OnInit, AfterViewInit { isDirty(): boolean { return this.searchTable.isDirty(); } - get isSMPIntegrationOn(){ + + get isSMPIntegrationOn() { return this.lookups.cachedApplicationConfig?.smlIntegrationOn } diff --git a/smp-angular/src/app/domain/keystore-edit-dialog/keystore-edit-dialog.component.ts b/smp-angular/src/app/domain/keystore-edit-dialog/keystore-edit-dialog.component.ts index ef16ddb0c..100eb7843 100644 --- a/smp-angular/src/app/domain/keystore-edit-dialog/keystore-edit-dialog.component.ts +++ b/smp-angular/src/app/domain/keystore-edit-dialog/keystore-edit-dialog.component.ts @@ -1,4 +1,4 @@ -import {AfterViewChecked, Component, Inject} from '@angular/core'; +import {AfterViewChecked, AfterViewInit, ChangeDetectorRef, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {FormBuilder} from "@angular/forms"; import {AlertMessageService} from "../../common/alert-message/alert-message.service"; @@ -31,7 +31,8 @@ export class KeystoreEditDialogComponent implements AfterViewChecked{ private dialogRef: MatDialogRef<KeystoreEditDialogComponent>, private alertService: AlertMessageService, @Inject(MAT_DIALOG_DATA) public data: any, - private fb: FormBuilder) { + private fb: FormBuilder, + private changeDetector: ChangeDetectorRef) { this.formTitle = "Keystore edit dialog"; } @@ -39,6 +40,8 @@ export class KeystoreEditDialogComponent implements AfterViewChecked{ // fix bug updating the columns //https://github.com/swimlane/ngx-datatable/issues/1266 window.dispatchEvent(new Event('resize')); + this.changeDetector.detectChanges(); + } onDeleteCertificateRowActionClicked(row) { diff --git a/smp-angular/src/app/domain/keystore-import-dialog/keystore-import-dialog.component.ts b/smp-angular/src/app/domain/keystore-import-dialog/keystore-import-dialog.component.ts index 349319dc4..56fb8b8d3 100644 --- a/smp-angular/src/app/domain/keystore-import-dialog/keystore-import-dialog.component.ts +++ b/smp-angular/src/app/domain/keystore-import-dialog/keystore-import-dialog.component.ts @@ -64,70 +64,8 @@ export class KeystoreImportDialogComponent { } }, err => { - this.alertService.exception('Error uploading keystore file ' + this.selectedFile.name, err); + this.alertService.exception('Error uploading keystore file ' + this.selectedFile.name, err.error?.errorDescription); } ) - - } - /* - - importKeystore() { - const headers = new HttpHeaders() - .set("Content-Type", "application/octet-stream"); - - const params: HttpParams = new HttpParams(); - params.set('keystoreType', this.dialogForm.controls['keystoreType'].value); - params.set('password', this.dialogForm.controls['password'].value); - let keystoreType = this.dialogForm.controls['keystoreType'].value; - let password = encodeURIComponent(this.dialogForm.controls['password'].value); - - - const currentUser: User = this.securityService.getCurrentUser(); - this.http.post<CertificateRo>(`${SmpConstants.REST_KEYSTORE}/${currentUser.id}/upload/${keystoreType}/${password}`, this.selectedFile, {headers,params }).subscribe((res: CertificateRo) => { - if (res ) { - this.alertService.success("Keystore "+this.selectedFile.name+ " imported!"); - this.lookups.refreshCertificateLookup(); - } else { - this.alertService.exception("Error occurred while reading certificate.", "Check if uploaded file has valid certificate type.", false); - } - }, - err => { - this.alertService.exception('Error uploading certificate file ' + this.selectedFile.name, err); - } - ) - - } - - - importKeystoreMultipart() { - const headers = new HttpHeaders() - .set("Content-Type", "multipart/form-data"); - - const params: HttpParams = new HttpParams(); - params.set('keystoreType', this.dialogForm.controls['keystoreType'].value); - params.set('password', this.dialogForm.controls['password'].value); - let keystoreType = this.dialogForm.controls['keystoreType'].value; - let password = encodeURI(this.dialogForm.controls['password'].value); - - let input = new FormData(); -// Add your values in here - input.append('keystoreType',keystoreType); - input.append('password', password); - input.append('file', this.selectedFile); - - const currentUser: User = this.securityService.getCurrentUser(); - this.http.post<CertificateRo>(`${SmpConstants.REST_KEYSTORE}/${currentUser.id}/upload/`, input).subscribe((res: CertificateRo) => { - if (res ) { - this.alertService.success("Keystore "+this.selectedFile.name+ " imported!"); - } else { - this.alertService.exception("Error occurred while reading certificate.", "Check if uploaded file has valid certificate type.", false); - } - }, - err => { - this.alertService.exception('Error uploading certificate file ' + this.selectedFile.name, err); - } - ) - } -*/ } diff --git a/smp-angular/src/app/property/property.component.ts b/smp-angular/src/app/property/property.component.ts index 6cc76d264..89e13c470 100644 --- a/smp-angular/src/app/property/property.component.ts +++ b/smp-angular/src/app/property/property.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog} from '@angular/material/dialog'; import {AlertMessageService} from '../common/alert-message/alert-message.service'; @@ -16,7 +24,7 @@ import {SearchTableEntityStatus} from "../common/search-table/search-table-entit templateUrl: './property.component.html', styleUrls: ['./property.component.css'] }) -export class PropertyComponent implements OnInit, AfterViewInit { +export class PropertyComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>; @ViewChild('searchTable') searchTable: SearchTableComponent; @@ -32,7 +40,8 @@ export class PropertyComponent implements OnInit, AfterViewInit { protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertMessageService, - public dialog: MatDialog) { + public dialog: MatDialog, + private changeDetector: ChangeDetectorRef) { } @@ -42,7 +51,13 @@ export class PropertyComponent implements OnInit, AfterViewInit { ngOnInit() { this.propertyController = new PropertyController(this.http, this.lookups, this.dialog); + } + + ngAfterViewChecked() { + this.changeDetector.detectChanges(); + } + initColumns() { this.columnPicker.allColumns = [ { name: 'Property', @@ -65,7 +80,7 @@ export class PropertyComponent implements OnInit, AfterViewInit { } ngAfterViewInit() { - this.searchTable.tableColumnInit(); + this.initColumns(); } searchPropertyChanged() { diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.ts b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts index 13087690a..d9307336f 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, ChangeDetectorRef, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {AlertMessageService} from '../common/alert-message/alert-message.service'; @@ -15,7 +23,7 @@ import {SecurityService} from "../security/security.service"; templateUrl: './service-group-edit.component.html', styleUrls: ['./service-group-edit.component.css'] }) -export class ServiceGroupEditComponent implements OnInit, AfterViewInit { +export class ServiceGroupEditComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowMetadataAction', {static: true}) rowMetadataAction: TemplateRef<any> @ViewChild('rowActions', {static: true}) rowActions: TemplateRef<any>; @@ -45,7 +53,9 @@ export class ServiceGroupEditComponent implements OnInit, AfterViewInit { ngOnInit(): void { this.serviceGroupEditController = new ServiceGroupEditController(this.dialog); + } + initColumns() { this.columnPicker.allColumns = [ { name: 'Metadata', @@ -86,11 +96,15 @@ export class ServiceGroupEditComponent implements OnInit, AfterViewInit { sortable: false }, ]; - this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially); + this.searchTable.tableColumnInit(); + } + + ngAfterViewChecked() { + this.changeDetector.detectChanges(); } ngAfterViewInit(): void { - this.searchTable.tableColumnInit(); + this.initColumns(); } details(row: any) { diff --git a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts index 0b469e13c..bd1448a58 100644 --- a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts +++ b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts @@ -87,7 +87,7 @@ export class ServiceMetadataWizardDialogComponent { } }, err => { - this.alertService.exception('Error uploading certificate file ' + file.name, err); + this.alertService.exception('Error uploading certificate file ' +file.name, err.error?.errorDescription); } ); } diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.ts b/smp-angular/src/app/service-group-search/service-group-search.component.ts index 1d893e9d9..8b37f78ae 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.ts +++ b/smp-angular/src/app/service-group-search/service-group-search.component.ts @@ -1,5 +1,13 @@ ///<reference path="../smp.constants.ts"/> -import {AfterViewInit, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog} from '@angular/material/dialog'; import {AlertMessageService} from '../common/alert-message/alert-message.service'; @@ -14,7 +22,7 @@ import {SearchTableComponent} from "../common/search-table/search-table.componen templateUrl: './service-group-search.component.html', styleUrls: ['./service-group-search.component.css'] }) -export class ServiceGroupSearchComponent implements OnInit, AfterViewInit { +export class ServiceGroupSearchComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowSMPUrlLinkAction', {static: true}) rowSMPUrlLinkAction: TemplateRef<any> @ViewChild('rowActions', {static: true}) rowActions: TemplateRef<any>; @@ -30,7 +38,8 @@ export class ServiceGroupSearchComponent implements OnInit, AfterViewInit { protected http: HttpClient, protected alertService: AlertMessageService, - public dialog: MatDialog) { + public dialog: MatDialog, + private changeDetector: ChangeDetectorRef) { this.baseUrl = SmpConstants.REST_PUBLIC_SEARCH_SERVICE_GROUP; } @@ -41,7 +50,9 @@ export class ServiceGroupSearchComponent implements OnInit, AfterViewInit { ngOnInit(): void { this.serviceGroupSearchController = new ServiceGroupSearchController(this.dialog); + } + initColumns(): void { this.columnPicker.allColumns = [ { name: 'Metadata size', @@ -74,11 +85,15 @@ export class ServiceGroupSearchComponent implements OnInit, AfterViewInit { sortable: false }, ]; - this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially); + this.searchTable.tableColumnInit(); + } + + ngAfterViewChecked() { + this.changeDetector.detectChanges(); } ngAfterViewInit() { - this.searchTable.tableColumnInit(); + this.initColumns(); } createServiceGroupURL(row: any) { diff --git a/smp-angular/src/app/user/truststore-edit-dialog/truststore-edit-dialog.component.ts b/smp-angular/src/app/user/truststore-edit-dialog/truststore-edit-dialog.component.ts index 2e9589182..766444d40 100644 --- a/smp-angular/src/app/user/truststore-edit-dialog/truststore-edit-dialog.component.ts +++ b/smp-angular/src/app/user/truststore-edit-dialog/truststore-edit-dialog.component.ts @@ -1,4 +1,12 @@ -import {AfterViewChecked, AfterViewInit, Component, Inject, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + Inject, + TemplateRef, + ViewChild +} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {FormBuilder} from "@angular/forms"; import {AlertMessageService} from "../../common/alert-message/alert-message.service"; @@ -35,7 +43,8 @@ export class TruststoreEditDialogComponent implements AfterViewInit, AfterViewCh private dialogRef: MatDialogRef<TruststoreEditDialogComponent>, private alertService: AlertMessageService, @Inject(MAT_DIALOG_DATA) public data: any, - private fb: FormBuilder) { + private fb: FormBuilder, + private changeDetector: ChangeDetectorRef) { this.formTitle = "Truststore edit dialog"; // bind to trusted certificate list events this.lookups.onTrustedCertificateListRefreshEvent().subscribe((data) => { @@ -48,9 +57,16 @@ export class TruststoreEditDialogComponent implements AfterViewInit, AfterViewCh // fix bug updating the columns //https://github.com/swimlane/ngx-datatable/issues/1266 window.dispatchEvent(new Event('resize')); + this.changeDetector.detectChanges(); + } ngAfterViewInit(): void { + this.initColumns(); + this.refreshData(); + } + + initColumns(): void { this.tableColumns = [ { cellTemplate: this.rowIndex, @@ -75,8 +91,6 @@ export class TruststoreEditDialogComponent implements AfterViewInit, AfterViewCh cellTemplate: this.certificateRowActions, }, ]; - - this.refreshData(); } @@ -128,7 +142,7 @@ export class TruststoreEditDialogComponent implements AfterViewInit, AfterViewCh } }, err => { - this.alertService.exception('Error uploading certificate file ' + file.name, err); + this.alertService.exception('Error uploading certificate file ' + file.name, err.error?.errorDescription); } ); } 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 aec81251c..15c667989 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 @@ -300,7 +300,7 @@ export class UserDetailsDialogComponent { } }, err => { - this.alertService.exception('Error uploading certificate file ' + file.name, err); + this.alertService.exception('Error uploading certificate file ' + file.name, err.error?.errorDescription); } ); diff --git a/smp-angular/src/app/user/user.component.ts b/smp-angular/src/app/user/user.component.ts index 21c6a109b..67ba12aa1 100644 --- a/smp-angular/src/app/user/user.component.ts +++ b/smp-angular/src/app/user/user.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, + Component, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {AlertMessageService} from '../common/alert-message/alert-message.service'; @@ -15,7 +23,7 @@ import {SmpConstants} from "../smp.constants"; templateUrl: './user.component.html', styleUrls: ['./user.component.css'] }) -export class UserComponent implements OnInit, AfterViewInit { +export class UserComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>; @ViewChild('rowExtensionAction') rowExtensionAction: TemplateRef<any>; @@ -32,12 +40,15 @@ export class UserComponent implements OnInit, AfterViewInit { public securityService: SecurityService, protected http: HttpClient, protected alertService: AlertMessageService, - public dialog: MatDialog) { + public dialog: MatDialog, + private changeDetector: ChangeDetectorRef) { } ngOnInit() { this.userController = new UserController(this.http, this.lookups, this.dialog); + } + initColumns() { this.columnPicker.allColumns = [ { name: 'Username', @@ -59,17 +70,21 @@ export class UserComponent implements OnInit, AfterViewInit { canAutoResize: true }, ]; - this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => col.showInitially); + this.searchTable.tableColumnInit(); } ngAfterViewInit() { - this.searchTable.tableColumnInit(); + this.initColumns(); // if system admin refresh trust certificate list! if (this.securityService.isCurrentUserSystemAdmin()) { this.lookups.refreshTrustedCertificateLookup(); } } + ngAfterViewChecked() { + this.changeDetector.detectChanges(); + } + certCssClass(row) { if (row.certificate?.invalid) { diff --git a/smp-angular/src/app/user/user.service.ts b/smp-angular/src/app/user/user.service.ts index 2de88b322..574837c73 100644 --- a/smp-angular/src/app/user/user.service.ts +++ b/smp-angular/src/app/user/user.service.ts @@ -1,12 +1,9 @@ import {Injectable} from '@angular/core'; -import {Observable, of, Subject} from 'rxjs'; import {HttpClient} from '@angular/common/http'; -import {Role} from '../security/role.model'; import {SmpConstants} from "../smp.constants"; import {User} from "../security/user.model"; import {AlertMessageService} from "../common/alert-message/alert-message.service"; import {SecurityService} from "../security/security.service"; -import {AccessTokenRo} from "../common/dialogs/access-token-generation-dialog/access-token-ro.model"; @Injectable() export class UserService { @@ -15,7 +12,8 @@ export class UserService { private http: HttpClient, private securityService: SecurityService, private alertService: AlertMessageService, - ) { } + ) { + } updateUser(user: User) { this.http.put<User>(SmpConstants.REST_PUBLIC_USER_UPDATE.replace('{user-id}', user.userId), user).subscribe(response => { diff --git a/smp-examples/smp-spi-example/src/main/java/eu/europa/ec/smp/spi/ExamplePayloadValidatorSpiImpl.java b/smp-examples/smp-spi-example/src/main/java/eu/europa/ec/smp/spi/ExamplePayloadValidatorSpiImpl.java index 7a1140073..960012abe 100644 --- a/smp-examples/smp-spi-example/src/main/java/eu/europa/ec/smp/spi/ExamplePayloadValidatorSpiImpl.java +++ b/smp-examples/smp-spi-example/src/main/java/eu/europa/ec/smp/spi/ExamplePayloadValidatorSpiImpl.java @@ -30,6 +30,13 @@ public class ExamplePayloadValidatorSpiImpl implements PayloadValidatorSpi { LOG.info("*********************************************************************"); LOG.info("* Validate payload with size [{}] and mime type [{}]!", payload.available(), mimeType); LOG.info("**********************************************************************"); + if (payload.available() > 0 ) { + int firstChar = payload.read(); + // For the test if payload starts with an E throws and error + if (firstChar == (int)'E') { + throw new PayloadValidatorSpiException("This is invalid payload starting with E"); + } + } } catch (IOException e) { throw new PayloadValidatorSpiException("Can not read payload", e); } 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 909cb67bc..b08f03340 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 @@ -40,7 +40,7 @@ public enum SMPPropertyEnum { SML_URL("bdmsl.integration.url", "http://localhost:8080/edelivery-sml", "BDMSL (SML) endpoint", false, false, false, URL), SML_TLS_DISABLE_CN_CHECK("bdmsl.integration.tls.disableCNCheck", "false", "If SML Url is HTTPs - Disable CN check if needed.", false, false, false, BOOLEAN), SML_TLS_SERVER_CERT_SUBJECT_REGEXP("bdmsl.integration.tls.serverSubjectRegex", ".*", "Regular expression for server TLS certificate subject verification CertEx. .*CN=acc.edelivery.tech.ec.europa.eu.*.", false, false, false, REGEXP), - SML_TLS_TRUSTSTORE_USE_SYSTEM_DEFAULT("bdmsl.integration.tls.userSystemDefaultTruststore", "false", "If true use system default truststore for trusting TLS server certificate (Legacy behaviour to SMP 4.1 version), else use SMP truststore", false, false, false, BOOLEAN), + SML_TLS_TRUSTSTORE_USE_SYSTEM_DEFAULT("bdmsl.integration.tls.useSystemDefaultTruststore", "false", "If true use system default truststore for trusting TLS server certificate (Legacy behaviour to SMP 4.1 version), else use SMP truststore", false, false, false, BOOLEAN), SML_LOGICAL_ADDRESS("bdmsl.integration.logical.address", "http://localhost:8080/smp/", "Logical SMP endpoint which will be registered on SML when registering new domain", false, false, false, URL), SML_PHYSICAL_ADDRESS("bdmsl.integration.physical.address", "0.0.0.0", "Physical SMP endpoint which will be registered on SML when registering new domain.", false, false, false, STRING), // keystore truststore @@ -55,7 +55,7 @@ public enum SMPPropertyEnum { ENCRYPTION_FILENAME("encryption.key.filename", "encryptionPrivateKey.private", "Key filename to encrypt passwords", false, false, true, FILENAME), KEYSTORE_PASSWORD_DECRYPTED("smp.keystore.password.decrypted", "", "Only for backup purposes when password is automatically created. Store password somewhere save and delete this entry!", false, false, false, STRING), TRUSTSTORE_PASSWORD_DECRYPTED("smp.truststore.password.decrypted", "", "Only for backup purposes when password is automatically created. Store password somewhere save and delete this entry!", false, false, false, STRING), - CERTIFICATE_ALLOWED_CERTIFICATEPOLICY_OIDS("smp.certificate.validation.allowedCertificatePolicyOIDs","","List of certificate policy OIDs separated by | where at least one must be in the CertifictePolicy extension", false, false,false, STRING), + CERTIFICATE_ALLOWED_CERTIFICATEPOLICY_OIDS("smp.certificate.validation.allowedCertificatePolicyOIDs","","List of certificate policy OIDs separated by | where at least one must be in the CertifictePolicy extension", false, false,false, LIST_STRING), CERTIFICATE_SUBJECT_REGULAR_EXPRESSION("smp.certificate.validation.subjectRegex",".*","Regular expression to validate subject of the certificate", false, false,false, REGEXP), SMP_PROPERTY_REFRESH_CRON("smp.property.refresh.cronJobExpression", "0 48 */1 * * *", "Property refresh cron expression (def 12 minutes to each hour). Property change is refreshed at restart!", false, false, false, CRON_EXPRESSION), diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java index a15f4ce7b..f95794a63 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java @@ -57,11 +57,11 @@ public enum ErrorCode { // XML_SIGNING_EXCEPTION (500,"SMP:500",ErrorBusinessCode.TECHNICAL,"Error occurred while signing response!"), - JAXB_INITIALIZATION (500,"SMP:511",ErrorBusinessCode.TECHNICAL, "Could not create Unmarshaller for class %s!"), - XML_PARSE_EXCEPTION (500,"SMP:512",ErrorBusinessCode.TECHNICAL, "Error occurred while parsing input stream for %s. Error: %s!"), - INVALID_REQUEST(400,"SMP:513",ErrorBusinessCode.TECHNICAL, "Invalid request %s. Error: %s!"), - INTERNAL_ERROR (500,"SMP:514",ErrorBusinessCode.TECHNICAL, "Internal error %s. Error: %s!"), - CERTIFICATE_ERROR (500,"SMP:515",ErrorBusinessCode.TECHNICAL, "Certificate error %s. Error: %s!"), + JAXB_INITIALIZATION (500,"SMP:511",ErrorBusinessCode.TECHNICAL, "Could not create Unmarshaller for class [%s]!"), + XML_PARSE_EXCEPTION (500,"SMP:512",ErrorBusinessCode.TECHNICAL, "Error occurred while parsing input stream for [%s]. Error: %s!"), + INVALID_REQUEST(400,"SMP:513",ErrorBusinessCode.TECHNICAL, "Invalid request [%s]. Error: %s!"), + INTERNAL_ERROR (500,"SMP:514",ErrorBusinessCode.TECHNICAL, "Internal error [%s]. Error: %s!"), + CERTIFICATE_ERROR (500,"SMP:515",ErrorBusinessCode.TECHNICAL, "Certificate error [%s]. Error: %s!"), CONFIGURATION_ERROR (500,"SMP:516",ErrorBusinessCode.TECHNICAL, "Configuration error: %s!"), diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CRLVerifierService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CRLVerifierService.java index 56ee3693a..e69a57f7b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CRLVerifierService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/CRLVerifierService.java @@ -153,13 +153,13 @@ public class CRLVerifierService { crl = (X509CRL) cf.generateCRL(crlStream); } } catch (IOException e) { - exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Can not download CRL '" + crlURL + exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Can not download CRL '" + crlURL+"'" , ExceptionUtils.getRootCauseMessage(e), e); } catch (CertificateException e) { - exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "CRL list is not supported '" + crlURL + exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "CRL list is not supported '" + crlURL+"'" , ExceptionUtils.getRootCauseMessage(e), e); } catch (CRLException e) { - exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "CRL can not be read: '" + crlURL + exception = new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "CRL can not be read: '" + crlURL+"'" , ExceptionUtils.getRootCauseMessage(e), e); } catch (SMPRuntimeException exc) { exception = exc; @@ -198,7 +198,7 @@ public class CRLVerifierService { } return inputStream; } catch (Exception exc) { - throw new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Error occurred while downloading CRL:'" + crlURL, ExceptionUtils.getRootCauseMessage(exc)); + throw new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Error occurred while downloading CRL:'" + crlURL+"'", ExceptionUtils.getRootCauseMessage(exc) ); } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorService.java index 239509e48..eed736b21 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorService.java @@ -7,6 +7,7 @@ import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.smp.spi.PayloadValidatorSpi; import eu.europa.ec.smp.spi.exceptions.PayloadValidatorSpiException; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Marker; import org.springframework.stereotype.Service; import java.io.InputStream; @@ -14,6 +15,8 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import static eu.europa.ec.edelivery.smp.logging.SMPLogger.SECURITY_MARKER; + /** * @author Joze Rihtarsic @@ -50,7 +53,8 @@ public class PayloadValidatorService { validatorSpi.validatePayload(payload, mimeType); } } catch (PayloadValidatorSpiException e) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "Content validation failed", ExceptionUtils.getRootCauseMessage(e),e); + LOG.error(SECURITY_MARKER,"Content validation failed: ["+ExceptionUtils.getRootCauseMessage(e)+"]" , e ); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST,"Upload payload", "Content validation failed"); } } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java index ee0b595a5..278c26869 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UITruststoreService.java @@ -8,7 +8,6 @@ import eu.europa.ec.edelivery.smp.data.ui.CertificateRO; import eu.europa.ec.edelivery.smp.exceptions.CertificateNotTrustedException; 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.text.DistinguishedNamesCodingUtil; @@ -41,6 +40,7 @@ import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static eu.europa.ec.edelivery.smp.logging.SMPMessageCode.SEC_USER_CERT_INVALID; import static java.util.Collections.list; import static java.util.Locale.US; @@ -209,15 +209,24 @@ public class UITruststoreService { cro.setInvalid(false); cro.setInvalidReason(null); } catch (CertificateExpiredException ex) { + LOG.securityError(SEC_USER_CERT_INVALID, cro.getCertificateId(), ex.getMessage()); cro.setInvalidReason("Certificate is expired!"); } catch (CertificateNotYetValidException ex) { + LOG.securityError(SEC_USER_CERT_INVALID, cro.getCertificateId(), ex.getMessage()); cro.setInvalidReason("Certificate is not yet valid!"); } catch (CertificateRevokedException ex) { + LOG.securityError(SEC_USER_CERT_INVALID, cro.getCertificateId(), ex.getMessage()); cro.setInvalidReason("Certificate is revoked!"); } catch (CertificateNotTrustedException ex) { + LOG.securityError(SEC_USER_CERT_INVALID, cro.getCertificateId(), ex.getMessage()); cro.setInvalidReason("Certificate is not trusted!"); } catch (CertificateException e) { - cro.setInvalidReason(ExceptionUtils.getRootCauseMessage(e)); + LOG.securityError(SEC_USER_CERT_INVALID, e, cro.getCertificateId(), e.getMessage()); + if (ExceptionUtils.getRootCause(e) instanceof CertPathValidatorException) { + cro.setInvalidReason("Certificate is not trusted! Invalid certificate policy path!"); + } else { + cro.setInvalidReason(e.getMessage()); + } } } return cro; @@ -241,7 +250,7 @@ public class UITruststoreService { CertificateValidator certificateValidator = new CertificateValidator( null, truststore, subjectRegExp != null ? subjectRegExp.pattern() : null, - configurationService.getAllowedCertificatePolicies()); + allowedCertificatePolicies != null ? allowedCertificatePolicies : Collections.emptyList()); LOG.debug("Validate certificate with truststore, subject regexp [{}] and allowed certificate policies [{}]", subjectRegExp, allowedCertificatePolicies); certificateValidator.validateCertificate(x509Certificate); } @@ -261,7 +270,7 @@ public class UITruststoreService { } - if (trustStore!=null) { + if (trustStore != null) { validateCertificateWithTruststore(cert); } else { LOG.warn("Use legacy certificate validation without truststore. Please configure truststore to increase security"); @@ -315,7 +324,7 @@ public class UITruststoreService { } catch (CertificateRevokedException ex) { String msg = "Certificate: '" + cert.getCertificateId() + "'" + " is revoked!"; - LOG.securityWarn(SMPMessageCode.SEC_USER_CERT_INVALID, cert.getCertificateId(), msg, ex); + LOG.securityWarn(SEC_USER_CERT_INVALID, cert.getCertificateId(), msg, ex); throw new CertificateException(msg); } catch (Throwable th) { String msg = "Error occurred while validating CRL for certificate!"; diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CRLVerifierServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CRLVerifierServiceTest.java index 960086c64..48c7d65a9 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CRLVerifierServiceTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/CRLVerifierServiceTest.java @@ -84,7 +84,7 @@ public class CRLVerifierServiceTest extends AbstractServiceIntegrationTest { X509Certificate certificate = loadCertificate("smp-crl-test-all.pem"); expectedEx.expect(SMPRuntimeException.class); - expectedEx.expectMessage("Certificate error Error occurred while downloading CRL:'https://localhost/clr. Error: ConnectException: Connection refused (Connection refused)!"); + expectedEx.expectMessage("Certificate error [Error occurred while downloading CRL:'https://localhost/clr']. Error: ConnectException: Connection refused (Connection refused)!"); // when-then crlVerifierServiceInstance.verifyCertificateCRLs(certificate); @@ -125,10 +125,10 @@ public class CRLVerifierServiceTest extends AbstractServiceIntegrationTest { public void verifyCertificateCRLsRevokedSerialTestThrowIOExceptionHttps() throws CertificateException, IOException, CRLException { String crlURL = "https://localhost/crl"; - Mockito.doThrow(new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Can not download CRL '" + crlURL, "IOException: Can not access URL")).when(crlVerifierServiceInstance).downloadCRL("https://localhost/crl", true); + Mockito.doThrow(new SMPRuntimeException(ErrorCode.CERTIFICATE_ERROR, "Can not download CRL '" + crlURL+"'", "IOException: Can not access URL")).when(crlVerifierServiceInstance).downloadCRL("https://localhost/crl", true); expectedEx.expect(SMPRuntimeException.class); - expectedEx.expectMessage("Certificate error Can not download CRL 'https://localhost/crl. Error: IOException: Can not access URL!"); + expectedEx.expectMessage("Certificate error [Can not download CRL 'https://localhost/crl']. Error: IOException: Can not access URL!"); // when-then crlVerifierServiceInstance.verifyCertificateCRLs("11", "https://localhost/crl"); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorServiceTest.java index 5cdf77988..3b3603a8b 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorServiceTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/PayloadValidatorServiceTest.java @@ -77,6 +77,8 @@ public class PayloadValidatorServiceTest { assertThrows(SMPRuntimeException.class, () -> testInstance.validateUploadedContent(inputStream, mimeType)); assertEquals(ErrorCode.INVALID_REQUEST, smpRuntimeException.getErrorCode()); - MatcherAssert.assertThat(smpRuntimeException.getMessage(), CoreMatchers.containsString(spiException.getMessage())); + // generic error + assertEquals("Invalid request [Upload payload]. Error: Content validation failed!", smpRuntimeException.getMessage()); + } } \ No newline at end of file diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java index 88dbcfb7b..3b077ff86 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java @@ -313,7 +313,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest SMPRuntimeException result = assertThrows(SMPRuntimeException.class, () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword)); - MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request PasswordChange.")); + MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request [PasswordChange].")); } @Test @@ -327,7 +327,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest SMPRuntimeException result = assertThrows(SMPRuntimeException.class, () -> testInstance.updateUserPassword(authorizedUserId, userToUpdateId, authorizedPassword, newPassword)); - MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request UserId. Error: Can not find user id!")); + MatcherAssert.assertThat(result.getMessage(), CoreMatchers.containsString("Invalid request [UserId]. Error: Can not find user id!")); } @Test diff --git a/smp-webapp/src/main/resources/logback.xml b/smp-webapp/src/main/resources/logback.xml index d338d52ee..b9fbe615e 100644 --- a/smp-webapp/src/main/resources/logback.xml +++ b/smp-webapp/src/main/resources/logback.xml @@ -4,7 +4,6 @@ <!-- pattern definition --> <property name="encoderPattern" value="%d{ISO8601} [%X{smp_user}] [%X{smp_session_id}] [%X{smp_request_id}] [%thread] %5p %c{1}:%L - %m%n" scope="global"/> <property name="consolePattern" value="%d{ISO8601} [%X{smp_user}] [%X{smp_session_id}] [%X{smp_request_id}] [%thread] %5p %c{1}:%L - %m%n" scope="global"/> - <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.folder:-logs}/edelivery-smp.log</file> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> @@ -27,16 +26,12 @@ <pattern>${encoderPattern}</pattern> </encoder> </appender> - - - <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> <pattern>${consolePattern}</pattern> </encoder> </appender> - <logger name="eu.europa.ec.edelivery" level="DEBUG" /> <logger name="eu.europa.ec.smp" level="DEBUG" /> <logger name="org.springframework.security.cas" level="DEBUG" /> diff --git a/smp-webapp/src/main/smp-setup/logback.xml b/smp-webapp/src/main/smp-setup/logback.xml index 41767c186..855023009 100644 --- a/smp-webapp/src/main/smp-setup/logback.xml +++ b/smp-webapp/src/main/smp-setup/logback.xml @@ -1,10 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> - <configuration> <!-- pattern definition --> <property name="encoderPattern" value="%d{ISO8601} [%X{smp_user}] [%X{smp_session_id}] [%X{smp_request_id}] [%thread] %5p %c{1}:%L - %m%n" scope="global"/> <property name="consolePattern" value="%d{ISO8601} [%X{smp_user}] [%X{smp_session_id}] [%X{smp_request_id}] [%thread] %5p %c{1}:%L - %m%n" scope="global"/> - <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.folder:-logs}/edelivery-smp.log</file> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> @@ -27,16 +25,12 @@ <pattern>${encoderPattern}</pattern> </encoder> </appender> - - - <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <Target>System.out</Target> <encoder> <pattern>${consolePattern}</pattern> </encoder> </appender> - <logger name="eu.europa.ec.edelivery.smp" level="INFO" /> <root level="WARN"> <appender-ref ref="file"/> -- GitLab