diff --git a/smp-angular/src/app/alert/alert.component.ts b/smp-angular/src/app/alert/alert.component.ts index 120e2ea320306392a916d5b36622cfe11d2fd70c..d1f58000c3334d669076f75eae52c71528f558e3 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 6644f83169b65669d2739ed943aca32b7d715d63..8b4e34f9902b7e35027382a01add20849ee8926e 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 ef16ddb0c6a29a478ae03880ce7852d06141f614..100eb78437e811ca627b539159cb2b4b854f7dc7 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 349319dc4f6c2c44302b0f98f87da9a1ba76b9ce..56fb8b8d3b3757c0128c0dabb5630db5082295a1 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 6cc76d2642adc87b3257ec2b1803c77ce3795fd3..89e13c47042745ba0fce6c7949f04635c35124ff 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 13087690a47874abb9a69c9553ec05e2c4bfcd08..d9307336f0cc026c8e830b717c0f1ace5c96f793 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 0b469e13c81ede7ae404c70be9523435d0214f9b..bd1448a586485b480b7abd5108da6dc470144f22 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 1d893e9d9b5dcfe3822542407916b426ff7ebfe8..8b37f78ae72747f0276ee99760cd75d95a5a0fce 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 2e9589182435703560007c8b317a87d8cc60c98c..766444d409797dae5c6e652f279ebb6d1134690e 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 aec81251c721d30ff7b335a4ff080d7a3ae52336..15c667989b38a191ad3c0193d734932818df7188 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 21c6a109bc97c7ba5644799194d1a5542ab4a770..67ba12aa16a9ae78f212919651ec5b345d59d97c 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 2de88b3227ca8cf4b0b4aca4c714c2b652ee513f..574837c73d6bcf3812ba8a56acb28c5da7e48624 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 7a11400735821a03161188ab7b288676779a725d..960012abee69a524ef48641afe8f26c6388a5ee4 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 909cb67bc4af7fa74114d179aa891c05eac2627b..b08f0334009e99085576ed6cbbbea29884bb78fe 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 a15f4ce7bd2ce66a26a91dcc86ed08371d0250b2..f95794a63590e1840958d8b71a9bd28741b95277 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 56ee3693a3dcd6cf34907df117f2b51bb66903a5..e69a57f7b034305277f0da39a240dbd51d03755c 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 239509e48bcd593037e5535327c4fe95f61dce41..eed736b21bc704b0a721cbbc5ba85b5614a9d7f4 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 ee0b595a5bc9acc3c8c900670c707313bbf9977f..278c2686947545ab456a7b5ad284540c8d15a095 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 960086c64c2992ca949fb82acd215df9649d89cc..48c7d65a9476f98e344fa8495092fdf894d9b07c 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 5cdf7798831ef79a2f00f5d6cd3b1b4b3fa49e0e..3b3603a8b927f7d47861a77696e61e1da25ced3e 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 88dbcfb7bcb8dc12e65ff4b542784fee00195cbe..3b077ff86c14201aa470b2dd4397a07cffc5c807 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 d338d52eeca409b8384ce43953e81fc820c1b715..b9fbe615e826807b7e9be19ae3a6051cf524b790 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 41767c18636663607bc909d8f94d1cf538ef4fd1..855023009253b9545f7b82bc4b2df7f9d81fcefd 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"/>