diff --git a/smp-angular/src/app/common/global-lookups.ts b/smp-angular/src/app/common/global-lookups.ts index 1d8fa0d6255689f92eaa88b02d942d9c36c7031e..358721f0c0b9e45f6e24af6d65684b6394f36a34 100644 --- a/smp-angular/src/app/common/global-lookups.ts +++ b/smp-angular/src/app/common/global-lookups.ts @@ -1,69 +1,72 @@ import {Injectable, OnInit} from '@angular/core'; import {HttpClient, HttpParams} from "@angular/common/http"; -import {DomainRo} from "../domain/domain-ro.model"; import {SearchTableResult} from "./search-table/search-table-result.model"; import {SmpConstants} from "../smp.constants"; import {Observable} from "rxjs/internal/Observable"; import {UserRo} from "../user/user-ro.model"; import {SecurityService} from "../security/security.service"; +import {Role} from "../security/role.model"; +import {AlertService} from "../alert/alert.service"; /** * Purpose of object is to fetch lookups as domains and users */ @Injectable() -export class GlobalLookups implements OnInit { +export class GlobalLookups implements OnInit { - domainObserver: Observable< SearchTableResult> - userObserver: Observable< SearchTableResult> + domainObserver: Observable<SearchTableResult> + userObserver: Observable<SearchTableResult> cachedDomainList: Array<any> = []; - cachedUserList: Array<any> = []; + cachedServiceGroupOwnerList: Array<any> = []; - constructor(protected securityService: SecurityService, protected http: HttpClient){ + constructor(protected alertService: AlertService, protected securityService: SecurityService, protected http: HttpClient) { this.refreshDomainLookup(); this.refreshUserLookup(); } ngOnInit() { + } - public refreshDomainLookup(){ + public refreshDomainLookup() { let params: HttpParams = new HttpParams() .set('page', '-1') .set('pageSize', '-1'); // init domains - this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN,{params}); + this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN, {params}); this.domainObserver.subscribe((domains: SearchTableResult) => { - let gotList = new Array(domains.serviceEntities.length) - .map((v, index) => domains.serviceEntities[index] as DomainRo); this.cachedDomainList = domains.serviceEntities.map(serviceEntity => { return {...serviceEntity} - + }, + (error:any) => { + this.alertService.error("Error occured while loading domain lookup [" + error + "].") }); }); } - public refreshUserLookup(){ - // call service if authenticated - if (this.securityService.isAuthenticated(false)) { + public refreshUserLookup() { + // call only for authenticated users. + if (this.securityService.isCurrentUserSMPAdmin()) { let params: HttpParams = new HttpParams() .set('page', '-1') - .set('pageSize', '-1'); + .set('pageSize', '-1') + .set('roles', Role.SMP_ADMIN +","+Role.SERVICE_GROUP_ADMIN); // init users this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER, {params}); this.userObserver.subscribe((users: SearchTableResult) => { - let gotList = new Array(users.serviceEntities.length) - .map((v, index) => users.serviceEntities[index] as UserRo); - this.cachedUserList = users.serviceEntities.map(serviceEntity => { + this.cachedServiceGroupOwnerList = users.serviceEntities.map(serviceEntity => { return {...serviceEntity} }); - }); + },(error:any) => { + // check if unauthorized + // just console try latter + console.log("Error occured while loading user owners lookup [" + error + "]"); + }); } } - - } diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html index 89af53a721970599eba5c8631914ff389e838896..d8e06ec6bd81a793ead9e9c55f9a6b740b550862 100644 --- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html +++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html @@ -1,64 +1,88 @@ <h2 mat-dialog-title>{{formTitle}}</h2> <mat-dialog-content> <form [formGroup]="domainForm"> - <mat-card> - <mat-card-title>Domain properties</mat-card-title> - <mat-card-content> + <mat-card> + <mat-card-title>Domain properties</mat-card-title> + <mat-card-content> <fieldset style="border: none;"> <mat-form-field style="width:100%"> - <input matInput placeholder="Domain Code (For WS API integration: the Domain property.)" name="domainCode" id="domainCode_id" + <input matInput placeholder="Domain Code (For WS API integration: the Domain property.)" name="domainCode" + id="domainCode_id" [formControl]="domainForm.controls['domainCode']" maxlength="255" required> - <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('pattern')" style="color:red; font-size: 70%"> - Domain code must contain only chars and numbers. + <div + *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('pattern')" + style="color:red; font-size: 70%"> + Domain code must contain only chars and numbers. </div> - <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('notInList')" style="color:red; font-size: 70%"> + <div + *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('notInList')" + style="color:red; font-size: 70%"> The Domain code already exists! </div> </mat-form-field> <mat-form-field style="width:100%"> - <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" name="smlSubdomain" id="smldomain_id" - [formControl]="domainForm.controls['smlSubdomain']" maxlength="255" > - <div *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('pattern')" style="color:red; font-size: 70%"> + <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" + name="smlSubdomain" id="smldomain_id" + [formControl]="domainForm.controls['smlSubdomain']" maxlength="255"> + <div + *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('pattern')" + style="color:red; font-size: 70%"> SML domain must be valid DNS part (AlphaNumeric with optional char - or must be empty for peppol). </div> - <div *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('notInList')" style="color:red; font-size: 70%"> + <div + *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('notInList')" + style="color:red; font-size: 70%"> The SML subdomain is already defined! </div> </mat-form-field> <mat-form-field style="width:100%"> - <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" id="signatureKeyAlias_id" - [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255" > + <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" + id="signatureKeyAlias_id" + [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255"> </mat-form-field> </fieldset> - </mat-card-content> - </mat-card> + </mat-card-content> + </mat-card> <mat-card> <mat-card-title>SML integration data</mat-card-title> <mat-card-content> <fieldset style="border: none;"> - <mat-form-field style="width:100%"> - <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" id="smlSMPId_id" - [formControl]="domainForm.controls['smlSmpId']" maxlength="255" required> - <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('pattern')" style="color:red; font-size: 70%"> - SML SMP ID must be valid DNS part (AlphaNumeric with optional char -)! - </div> - <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('notInList')" style="color:red; font-size: 70%"> - SML SMP ID already exists! - </div> - </mat-form-field> - <mat-form-field style="width:100%"> - <input matInput placeholder="ClientCert Header" name="Client certificate" id="smlClientHeader_id" - [formControl]="domainForm.controls['smlClientCertHeader']" maxlength="255" > - </mat-form-field> - <mat-form-field style="width:100%"> - <input matInput placeholder="ClientCert Alias" name="Client certificate" id="smlClientKeyAlias_id" - [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" > - </mat-form-field> - </fieldset> - <!-- label class="custom-file-upload"> - <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" > - <span class="custom-file-upload-inner">Import</span> - </label--> + <mat-form-field style="width:100%"> + <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" id="smlSMPId_id" + [formControl]="domainForm.controls['smlSmpId']" maxlength="255" required> + <div + *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('pattern')" + style="color:red; font-size: 70%"> + SML SMP ID must be valid DNS part (AlphaNumeric with optional char -)! + </div> + <div + *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('notInList')" + style="color:red; font-size: 70%"> + SML SMP ID already exists! + </div> + </mat-form-field> + <mat-form-field style="width:100%"> + <input matInput placeholder="ClientCert Header" name="Client certificate" id="smlClientHeader_id" + [formControl]="domainForm.controls['smlClientCertHeader']" maxlength="2000"> + </mat-form-field> + <label class="custom-file-upload"> + <input #fileInput type="file" style="display: inline-block;cursor: pointer; display: none;" + id="certificate-file-upload" accept=".cer,.crt,.pem,.der" + (change)="uploadCertificate($event)"> + <button mat-flat-button color="primary" + (click)="fileInput.click()" + >Generate 'ClientCert Header' from certificate + </button> + </label> + <mat-form-field style="width:100%"> + <input matInput placeholder="ClientCert Alias" name="Client certificate" id="smlClientKeyAlias_id" + [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255"> + </mat-form-field> + </fieldset> + <!-- label class="custom-file-upload"> + <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" > + <span class="custom-file-upload-inner">Import</span> + </label--> </mat-card-content> </mat-card> </form> @@ -78,5 +102,5 @@ </td> </tr> </table> -<div style="text-align: right; font-size: 70%">* required fields</div> +<div style="text-align: right; font-size: 70%">* required fields</div> diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts index 9c04e0d6138a8da74db013dfea8652b0e47520a0..9498787b743a62b85e868f11a87c8013b354aebb 100644 --- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts +++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts @@ -5,6 +5,8 @@ import {DomainRo} from "../domain-ro.model"; import {AlertService} from "../../alert/alert.service"; import {SearchTableEntityStatus} from "../../common/search-table/search-table-entity-status.model"; import {GlobalLookups} from "../../common/global-lookups"; +import {CertificateRo} from "../../user/certificate-ro.model"; +import {CertificateService} from "../../user/certificate.service"; @Component({ selector: 'domain-details-dialog', @@ -32,7 +34,8 @@ export class DomainDetailsDialogComponent { } } - constructor(private lookups: GlobalLookups, + constructor( private certificateService: CertificateService, + private lookups: GlobalLookups, private dialogRef: MatDialogRef<DomainDetailsDialogComponent>, private alertService: AlertService, @Inject(MAT_DIALOG_DATA) public data: any, @@ -131,5 +134,31 @@ export class DomainDetailsDialogComponent { this.current.signatureKeyAlias = event.target.value; } + uploadCertificate(event) { + const file = event.target.files[0]; + + const reader = new FileReader(); + reader.onload = (e) => { + this.certificateService.uploadCertificate$(reader.result).subscribe((res: CertificateRo) => { + if (res && res.certificateId){ + this.domainForm.patchValue({ + 'smlClientCertHeader': res.blueCoatHeader + }); + } else { + this.alertService.exception("Error occured while reading certificate.", "Check if uploaded file has valid certificate type?", false); + } + }, + err => { + this.alertService.exception('Error uploading certificate file ' + file.name, err); + } + ); + }; + reader.onerror = (err) => { + this.alertService.exception('Error reading certificate file ' + file.name, err); + }; + + reader.readAsBinaryString(file); + } + } diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html index a81f3ac6170ae4e2a78620aa078ad3377ae1c301..71b606b7c8d5813123eb676b04800b9a7dba09b2 100644 --- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html +++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html @@ -36,7 +36,7 @@ <mat-card> <mat-card-content> <mat-accordion> - <mat-expansion-panel [expanded]="true"> + <mat-expansion-panel *ngIf="securityService.isCurrentUserSMPAdmin()" [expanded]="true" > <mat-expansion-panel-header> <mat-panel-title>Owners* </mat-panel-title> @@ -56,13 +56,14 @@ [compareWith]="compareTableItemById" [formControl]="dialogForm.controls['users']" style="height: 200px; overflow-y: scroll; overflow-x: auto;"> - <mat-list-option *ngFor="let user of lookups?.cachedUserList" [value]='user'> - {{user.id}} - {{user.username?user.username:user.id}} + <!-- // if username is null then there must be an cerificate id! --> + <mat-list-option *ngFor="let user of lookups.cachedServiceGroupOwnerList" [value]='user'> + {{user.username?user.username:user.certificate.certificateId}} </mat-list-option> </mat-selection-list> </mat-expansion-panel> - <mat-expansion-panel > + <mat-expansion-panel [expanded]="!securityService.isCurrentUserSMPAdmin()"> <mat-expansion-panel-header> <mat-panel-title>Domains*</mat-panel-title> <mat-panel-description> diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts index c06b53371210d0e538d2b4a505449686dafa9337..448afe18b2216d6b0459cbd3d6c6ed6d9eb5049a 100644 --- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts @@ -14,6 +14,7 @@ import {DomainRo} from "../../domain/domain-ro.model"; import {ServiceGroupDomainEditRo} from "../service-group-domain-edit-ro.model"; import {ConfirmationDialogComponent} from "../../common/confirmation-dialog/confirmation-dialog.component"; import {SecurityService} from "../../security/security.service"; +import {UserRo} from "../../user/user-ro.model"; @Component({ selector: 'service-group-details', @@ -37,8 +38,8 @@ export class ServiceGroupDetailsDialogComponent implements OnInit { extensionValidationMessage: String = null; isExtensionValid: boolean = true; + userList: UserRo[]; - serviceGroupDomain: ServiceGroupDomainEditRo[]; minSelectedListCount(min: number) { @@ -60,6 +61,7 @@ export class ServiceGroupDetailsDialogComponent implements OnInit { private dialogFormBuilder: FormBuilder, private changeDetector: ChangeDetectorRef) { this.editMode = this.data.edit; + this.formTitle = this.editMode ? ServiceGroupDetailsDialogComponent.EDIT_MODE : ServiceGroupDetailsDialogComponent.NEW_MODE; this.current = this.editMode ? { 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 8eb457e4b9a0597bda3d043a6c86385083996b55..009bafcbd44a49876f1c044e2d7a3543ae1fd2dd 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 @@ -35,11 +35,16 @@ export class ServiceGroupEditComponent implements OnInit { public dialog: MatDialog, private changeDetector: ChangeDetectorRef) { + // if smp admin it needs to have update user list for detail dialog! + if (this.securityService.isCurrentUserSMPAdmin()) { + this.lookups.refreshUserLookup(); + } } ngOnInit() { + this.serviceGroupEditController = new ServiceGroupEditController(this.dialog); this.columnPicker.allColumns = [ diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts index 9c947ff4f88906d770175e79909370bd3afa982a..c688e7d4fc824688fa744b4db7e78c00e7942864 100644 --- a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts @@ -160,7 +160,7 @@ export class ServiceGroupMetadataDialogComponent implements OnInit { let exampleXML = '<ServiceMetadata xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">' + '\n <ServiceInformation>' + '\n <ParticipantIdentifier scheme="' + this.dialogForm.controls['participantScheme'].value + '">' + this.dialogForm.controls['participantIdentifier'].value + '</ParticipantIdentifier>' + - '\n <DocumentIdentifier scheme="' + this.dialogForm.controls['documentIdentifierScheme'].value + '">' + this.dialogForm.controls['documentIdentifier'].value + '</DocumentIdentifier>' + + '\n <DocumentIdentifier scheme="' + this.xmlSpecialChars(this.dialogForm.controls['documentIdentifierScheme'].value) + '">' + this.xmlSpecialChars(this.dialogForm.controls['documentIdentifier'].value) + '</DocumentIdentifier>' + '\n <ProcessList>' + '\n <Process>' + '\n <ProcessIdentifier scheme="[enterProcessType]">[enterProcessName]</ProcessIdentifier>' + @@ -180,6 +180,14 @@ export class ServiceGroupMetadataDialogComponent implements OnInit { this.dialogForm.controls['xmlContent'].setValue(exampleXML); } + xmlSpecialChars(unsafe) { + return !unsafe?'':unsafe + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """); + } + onServiceMetadataValidate() { let request: ServiceMetadataValidationEditRo = { @@ -196,7 +204,7 @@ export class ServiceGroupMetadataDialogComponent implements OnInit { this.metadataValidationMessage = res.errorMessage; this.isMetadataValid = false; } else { - this.metadataValidationMessage = "ServiceMetada is valid!"; + this.metadataValidationMessage = "Servicemetadata is valid!"; this.isMetadataValid = true; } diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.css b/smp-angular/src/app/service-group-search/service-group-search.component.css index 65c9eab51048787f6d1098fc3c1ecd438a6e86c4..67011f0e6d861f1f5c825d0b6cb9edc8d8f6e7e5 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.css +++ b/smp-angular/src/app/service-group-search/service-group-search.component.css @@ -17,7 +17,6 @@ overflow-y: scroll; } - /deep/ .inner-table { margin-left: 100px; width: 80%; @@ -32,3 +31,4 @@ height: auto !important;; line-height: unset !important; } + diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.html b/smp-angular/src/app/service-group-search/service-group-search.component.html index 5e0797c2ee9ae0099efada72f55b3e3005263bd8..b8995d6d5fac68f032f1787fa6c7479c0f531ed7 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.html +++ b/smp-angular/src/app/service-group-search/service-group-search.component.html @@ -57,8 +57,7 @@ </div> <div *ngIf="row.serviceMetadata.length !== 0"> <ngx-datatable - class='material striped' - style="width: 80%" + class='inner-table material striped' [loadingIndicator]="loading" [rows]='row.serviceMetadata' [columnMode]='"force"' diff --git a/smp-angular/src/app/user/certificate-ro.model.ts b/smp-angular/src/app/user/certificate-ro.model.ts index 14b2705c43bcec23b45a895d93bbded2b49d2156..5b996233e578f68656b0bd627eec5dd0fd748998 100644 --- a/smp-angular/src/app/user/certificate-ro.model.ts +++ b/smp-angular/src/app/user/certificate-ro.model.ts @@ -6,4 +6,5 @@ export interface CertificateRo { issuer: string; serialNumber: string; fingerprints: string; + blueCoatHeader?:string; } 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 66fff3fb6ad733ad9db2902b30f081646c404a37..32fab5b855403dbfade2afbeb8d89e2e28e1b4b6 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 @@ -46,6 +46,8 @@ id="username_id" maxlength="255" required> <div *ngIf="userForm.controls['username'].hasError('required') && userForm.controls['username'].touched" class="has-error">You should type an username</div> + <div *ngIf="userForm.controls['username'].hasError('pattern') && userForm.controls['username'].touched" + class="has-error">Username can only contain alphanumeric characters (letters A-Z, numbers 0-9) and must have from 4 to 32 characters!</div> </mat-form-field> <mat-slide-toggle *ngIf="editMode" mat-no-ink class="mat-primary" [formControl]="userForm.controls['passwordToggle']" 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 40879322e604c4fb3bc5e24c163392d275c289bf..e78331e56079130b38e5a604c1cd258fb1a1b089 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 @@ -27,6 +27,8 @@ export class UserDetailsDialogComponent { readonly emailPattern = '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'; readonly passwordPattern = '^(?=.*[A-Z])(?=.*[ !#$%&\'()*+,-./:;<=>?@\\[^_`{|}~\\\]"])(?=.*[0-9])(?=.*[a-z]).{8,32}$'; readonly dateFormat: string = 'yyyy-MM-dd HH:mm:ssZ'; + readonly usernamePattern='^[a-zA-Z0-9]{4,32}$'; + editMode: boolean; formTitle: string; @@ -109,7 +111,8 @@ export class UserDetailsDialogComponent { // username/password authentication 'userToggle': new FormControl(bUserPasswordAuthentication), 'passwordToggle': new FormControl({value: bSetPassword, disabled:!bUserPasswordAuthentication}), - 'username': new FormControl({ value: '', disabled: this.editMode || !bUserPasswordAuthentication }, this.editMode ? Validators.nullValidator : null), + 'username': new FormControl({ value: '', disabled: this.editMode || !bUserPasswordAuthentication }, + !this.editMode ? [Validators.nullValidator, Validators.pattern(this.usernamePattern)] : null), 'password': new FormControl({ value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, [Validators.required, Validators.pattern(this.passwordPattern)]), 'confirmation': new FormControl({ value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, @@ -146,7 +149,7 @@ export class UserDetailsDialogComponent { this.userForm.controls['userToggle'].disable(); } -/* Do not need retrieve roles from server because client must alreay be aware of +/* Do not need retrieve roles from server because client must already be aware of the roles... this.userService.getUserRoles$().subscribe(userRoles => { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/BaseEntity.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/BaseEntity.java index b5bedf13d35e248214a1e4df7f96f0cd93342966..ecad959d5a1ed5e476c6cb9f4609131c9c2810d4 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/BaseEntity.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/BaseEntity.java @@ -13,14 +13,15 @@ package eu.europa.ec.edelivery.smp.data.model; +import java.io.Serializable; import java.time.LocalDateTime; import java.util.Objects; /** * Created by gutowpa on 23/01/2018. */ -public abstract class BaseEntity { - +public abstract class BaseEntity implements Serializable { + private static final long serialVersionUID = 1905122041950251200L; public abstract Object getId(); @@ -41,4 +42,6 @@ public abstract class BaseEntity { public int hashCode() { return Objects.hash(getId()); } + + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java index b005771bc587246d63ac1c3760c72063d054b7f0..5653f2aba721725c1a218109f43a7448c2c5f165 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java @@ -33,9 +33,9 @@ import java.time.LocalDateTime; @NamedNativeQuery(name = "DBDomainDeleteValidation.validateDomainUsage", resultSetMapping = "DBDomainDeleteValidationMapping", query = "select D.ID as id, D.DOMAIN_CODE as domainCode, D.SML_SUBDOMAIN as smlSubdomain, COUNT(SGD.ID) as useCount " + - " from SMP_DOMAIN D INNER JOIN SMP_SERVICE_GROUP_DOMAIN SGD ON (D.ID =SGD.FK_DOMAIN_ID) " + - " WHERE D.ID IN (:domainIds)" + - "GROUP BY D.DOMAIN_CODE, D.SML_SUBDOMAIN;"), + " from SMP_DOMAIN D INNER JOIN SMP_SERVICE_GROUP_DOMAIN SGD ON (D.ID =SGD.FK_DOMAIN_ID) " + + " WHERE D.ID IN (:domainIds)" + + " GROUP BY D.ID, D.DOMAIN_CODE, D.SML_SUBDOMAIN"), }) @SqlResultSetMapping(name = "DBDomainDeleteValidationMapping", classes = { @ConstructorResult(targetClass = DBDomainDeleteValidation.class, @@ -60,7 +60,7 @@ public class DBDomain extends BaseEntity { String smlSmpId; @Column(name = "SML_PARTC_IDENT_REGEXP", length = CommonColumnsLengths.MAX_FREE_TEXT_LENGTH) String smlParticipantIdentifierRegExp; - @Column(name = "SML_CLIENT_CERT_HEADER", length = CommonColumnsLengths.MAX_CERT_ALIAS_LENGTH) + @Column(name = "SML_CLIENT_CERT_HEADER", length = CommonColumnsLengths.MAX_FREE_TEXT_LENGTH) String smlClientCertHeader; @Column(name = "SML_CLIENT_KEY_ALIAS", length = CommonColumnsLengths.MAX_CERT_ALIAS_LENGTH) String smlClientKeyAlias; diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java index 572a4c3cf6dd542e98f3f59a96e5ad7252cf73d2..91d97a38ce792269ee3b211439ff2505f8c309d6 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java @@ -17,6 +17,9 @@ public class CertificateRO extends BaseRO { private String issuer; private String serialNumber; private String encodedValue; + private String blueCoatHeader; + + @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:mm", timezone="CET") private Date validFrom; @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:mm", timezone="CET") @@ -84,4 +87,12 @@ public class CertificateRO extends BaseRO { public void setEncodedValue(String encodedValue) { this.encodedValue = encodedValue; } + + public String getBlueCoatHeader() { + return blueCoatHeader; + } + + public void setBlueCoatHeader(String blueCoatHeader) { + this.blueCoatHeader = blueCoatHeader; + } } 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 488a219316e6f2237642be39e7e7509eb99757b2..f57ca7c311f623725bae9213f196d53b5694dda8 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 @@ -19,16 +19,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import sun.java2d.pipe.SpanShapeRenderer; import java.io.*; import java.math.BigInteger; +import java.net.URLEncoder; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.sql.Date; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.util.Arrays; import java.util.Base64; import java.util.List; @@ -40,6 +44,8 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { private static final byte[] S_PEM_START_TAG = "-----BEGIN CERTIFICATE-----\n".getBytes(); private static final byte[] S_PEM_END_TAG = "\n-----END CERTIFICATE-----".getBytes(); + private static final String S_BLUECOAT_DATEFORMAT ="MMM dd HH:mm:ss yyyy"; + @Autowired UserDao userDao; @@ -135,13 +141,39 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { cro.setValidFrom(cert.getNotBefore()); cro.setValidTo(cert.getNotAfter()); cro.setEncodedValue(Base64.getMimeEncoder().encodeToString(cert.getEncoded())); + // generate bluecoat header + SimpleDateFormat sdf = new SimpleDateFormat(S_BLUECOAT_DATEFORMAT); + StringWriter sw = new StringWriter(); + sw.write("sno="); + sw.write(serial.toString(16)); + sw.write("&subject="); + sw.write(urlEnodeString(subject)); + sw.write("&validfrom="); + sw.write(urlEnodeString(sdf.format(cert.getNotBefore())+" GTM")); + sw.write("&validto="); + sw.write(urlEnodeString(sdf.format(cert.getNotAfter())+" GTM")); + sw.write("&issuer="); + sw.write(urlEnodeString(issuer)); + cro.setBlueCoatHeader(sw.toString()); return cro; } + private String urlEnodeString(String val){ + if (StringUtils.isBlank(val)){ + return ""; + } else { + try { + return URLEncoder.encode(val, "UTF-8"); + } catch (UnsupportedEncodingException e) { + LOG.error("Error occured while url encoding the certificate string:" + val, e ); + } + } + return ""; + } + public boolean isCertificatePemEncoded(byte[] certData) { if (certData != null && certData.length > S_PEM_START_TAG.length) { - for (int i = 0; i < certData.length; i++) { if (certData[i] != S_PEM_START_TAG[i]) { return false; @@ -161,9 +193,11 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { */ public ByteArrayInputStream createPEMFormat(byte[] certData) throws IOException { ByteArrayInputStream is; - if (isCertificatePemEncoded(certData)) { - is = new ByteArrayInputStream(certData); + byte[] pemBuff = getPemEncodedString(certData); + if (pemBuff!=null) { + is = new ByteArrayInputStream(pemBuff); } else { + // try to encode ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(S_PEM_START_TAG); bos.write(Base64.getMimeEncoder().encode(certData)); @@ -173,6 +207,46 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { return is; } + /** + * pem encoded cartificate can have header_?? this code finds the certificate part and return the part + * @param buff + * @return + */ + private byte[] getPemEncodedString(byte[] buff){ + int iStart = indexOf(buff, S_PEM_START_TAG, 0); + if (iStart < 0){ + return null; + } + int iEnd = indexOf(buff, S_PEM_END_TAG, iStart); + if (iEnd<=iStart){ + return null; + } + return Arrays.copyOfRange(buff, iStart, iEnd + S_PEM_END_TAG.length); + + + + } + + /** + * Check if file contains bytearraz + * @param outerArray + * @param smallerArray + * @return + */ + public int indexOf(byte[] outerArray, byte[] smallerArray, int iStart) { + for(int i = iStart; i < outerArray.length - smallerArray.length+1; ++i) { + boolean found = true; + for(int j = 0; j < smallerArray.length; ++j) { + if (outerArray[i+j] != smallerArray[j]) { + found = false; + break; + } + } + if (found) return i; + } + return -1; + } + public String getCertificateIdFromCertificate(String subject, String issuer, BigInteger serial) { return new PreAuthenticatedCertificatePrincipal(subject, issuer, serial).getName(); } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/UserFilter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/UserFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..78d77508ca0bd65bc3a853ae36a5237474743b61 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/UserFilter.java @@ -0,0 +1,18 @@ +package eu.europa.ec.edelivery.smp.services.ui.filters; + +import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBUser; + +import java.util.List; + +public class UserFilter { + List<String> roleList; + + public List<String> getRoleList() { + return roleList; + } + + public void setRoleList(List<String> roles) { + this.roleList = roles; + } +} 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 c8ca20248fc23798dcaba5f68dcb7dffb73eab2a..a261fdc55c9af6f6ac8031f2ca2bfa91b82806f1 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 @@ -308,6 +308,24 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertTrue(cer.getValidFrom().before(cer.getValidTo())); } + @Test + public void testGetCertificateDataPEMWithHeader() throws IOException, CertificateException { + // given + byte[] buff = IOUtils.toByteArray(UIUserServiceIntegrationTest.class.getResourceAsStream("/truststore/pem-with-header.crt")); + // when + CertificateRO cer = testInstance.getCertificateData(buff); + //then + assertEquals("CN=alice,O=www.freelan.org,C=FR:0000000000000001", cer.getCertificateId()); + assertEquals("EMAILADDRESS=contact@freelan.org, CN=Freelan Sample Certificate Authority, OU=freelan, O=www.freelan.org, L=Strasbourg, ST=Alsace, C=FR", cer.getIssuer()); + assertEquals("EMAILADDRESS=contact@freelan.org, CN=alice, OU=freelan, O=www.freelan.org, ST=Alsace, C=FR", cer.getSubject()); + assertEquals("1", cer.getSerialNumber()); + assertNotNull(cer.getValidFrom()); + assertNotNull(cer.getValidTo()); + assertTrue(cer.getValidFrom().before(cer.getValidTo())); + } + + + @Test public void testGetCertificateDataDER() throws IOException, CertificateException { // given diff --git a/smp-server-library/src/test/resources/truststore/pem-with-header.crt b/smp-server-library/src/test/resources/truststore/pem-with-header.crt new file mode 100644 index 0000000000000000000000000000000000000000..6919b65b8150217800119c726a46bb52339a85fc --- /dev/null +++ b/smp-server-library/src/test/resources/truststore/pem-with-header.crt @@ -0,0 +1,125 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Alsace, L=Strasbourg, O=www.freelan.org, OU=freelan, CN=Freelan Sample Certificate Authority/emailAddress=contact@freelan.org + Validity + Not Before: Apr 27 10:31:18 2012 GMT + Not After : Apr 25 10:31:18 2022 GMT + Subject: C=FR, ST=Alsace, O=www.freelan.org, OU=freelan, CN=alice/emailAddress=contact@freelan.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:dd:6d:bd:f8:80:fa:d7:de:1b:1f:a7:a3:2e:b2: + 02:e2:16:f6:52:0a:3c:bf:a6:42:f8:ca:dc:93:67: + 4d:60:c3:4f:8d:c3:8a:00:1b:f1:c4:4b:41:6a:69: + d2:69:e5:3f:21:8e:c5:0b:f8:22:37:ad:b6:2c:4b: + 55:ff:7a:03:72:bb:9a:d3:ec:96:b9:56:9f:cb:19: + 99:c9:32:94:6f:8f:c6:52:06:9f:45:03:df:fd:e8: + 97:f6:ea:d6:ba:bb:48:2b:b5:e0:34:61:4d:52:36: + 0f:ab:87:52:25:03:cf:87:00:87:13:f2:ca:03:29: + 16:9d:90:57:46:b5:f4:0e:ae:17:c8:0a:4d:92:ed: + 08:a6:32:23:11:71:fe:f2:2c:44:d7:6c:07:f3:0b: + 7b:0c:4b:dd:3b:b4:f7:37:70:9f:51:b6:88:4e:5d: + 6a:05:7f:8d:9b:66:7a:ab:80:20:fe:ee:6b:97:c3: + 49:7d:78:3b:d5:99:97:03:75:ce:8f:bc:c5:be:9c: + 9a:a5:12:19:70:f9:a4:bd:96:27:ed:23:02:a7:c7: + 57:c9:71:cf:76:94:a2:21:62:f6:b8:1d:ca:88:ee: + 09:ad:46:2f:b7:61:b3:2c:15:13:86:9f:a5:35:26: + 5a:67:f4:37:c8:e6:80:01:49:0e:c7:ed:61:d3:cd: + bc:e4:f8:be:3f:c9:4e:f8:7d:97:89:ce:12:bc:ca: + b5:c6:d2:e0:d9:b3:68:3c:2e:4a:9d:b4:5f:b8:53: + ee:50:3d:bf:dd:d4:a2:8a:b6:a0:27:ab:98:0c:b3: + b2:58:90:e2:bc:a1:ad:ff:bd:8e:55:31:0f:00:bf: + 68:e9:3d:a9:19:9a:f0:6d:0b:a2:14:6a:c6:4c:c6: + 4e:bd:63:12:a5:0b:4d:97:eb:42:09:79:53:e2:65: + aa:24:34:70:b8:c1:ab:23:80:e7:9c:6c:ed:dc:82: + aa:37:04:b8:43:2a:3d:2a:a8:cc:20:fc:27:5d:90: + 26:58:f9:b7:14:e2:9e:e2:c1:70:73:97:e9:6b:02: + 8e:d3:52:59:7b:00:ec:61:30:f1:56:3f:9c:c1:7c: + 05:c5:b1:36:c8:18:85:cf:61:40:1f:07:e8:a7:06: + 87:df:9a:77:0b:a9:64:72:03:f6:93:fc:e0:02:59: + c1:96:ec:c0:09:42:3e:30:a2:7f:1b:48:2f:fe:e0: + 21:8f:53:87:25:0d:cb:ea:49:f5:4a:9b:d0:e3:5f: + ee:78:18:e5:ba:71:31:a9:04:98:0f:b1:ad:67:52: + a0:f2:e3:9c:ab:6a:fe:58:84:84:dd:07:3d:32:94: + 05:16:45:15:96:59:a0:58:6c:18:0e:e3:77:66:c7: + b3:f7:99 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 59:5F:C9:13:BA:1B:CC:B9:A8:41:4A:8A:49:79:6A:36:F6:7D:3E:D7 + X509v3 Authority Key Identifier: + keyid:23:6C:2D:3D:3E:29:5D:78:B8:6C:3E:AA:E2:BB:2E:1E:6C:87:F2:53 + + Signature Algorithm: sha1WithRSAEncryption + 13:e7:02:45:3e:a7:ab:bd:b8:da:e7:ef:74:88:ac:62:d5:dd: + 10:56:d5:46:07:ec:fa:6a:80:0c:b9:62:be:aa:08:b4:be:0b: + eb:9a:ef:68:b7:69:6f:4d:20:92:9d:18:63:7a:23:f4:48:87: + 6a:14:c3:91:98:1b:4e:08:59:3f:91:80:e9:f4:cf:fd:d5:bf: + af:4b:e4:bd:78:09:71:ac:d0:81:e5:53:9f:3e:ac:44:3e:9f: + f0:bf:5a:c1:70:4e:06:04:ef:dc:e8:77:05:a2:7d:c5:fa:80: + 58:0a:c5:10:6d:90:ca:49:26:71:84:39:b7:9a:3e:e9:6f:ae: + c5:35:b6:5b:24:8c:c9:ef:41:c3:b1:17:b6:3b:4e:28:89:3c: + 7e:87:a8:3a:a5:6d:dc:39:03:20:20:0b:c5:80:a3:79:13:1e: + f6:ec:ae:36:df:40:74:34:87:46:93:3b:a3:e0:a4:8c:2f:43: + 4c:b2:54:80:71:76:78:d4:ea:12:28:d8:f2:e3:80:55:11:9b: + f4:65:dc:53:0e:b4:4c:e0:4c:09:b4:dc:a0:80:5c:e6:b5:3b: + 95:d3:69:e4:52:3d:5b:61:86:02:e5:fd:0b:00:3a:fa:b3:45: + cc:c9:a3:64:f2:dc:25:59:89:58:0d:9e:6e:28:3a:55:45:50: + 5f:88:67:2a:d2:e2:48:cc:8b:de:9a:1b:93:ae:87:e1:f2:90: + 50:40:d9:0f:44:31:53:46:ad:62:4e:8d:48:86:19:77:fc:59: + 75:91:79:35:59:1d:e3:4e:33:5b:e2:31:d7:ee:52:28:5f:0a: + 70:a7:be:bb:1c:03:ca:1a:18:d0:f5:c1:5b:9c:73:04:b6:4a: + e8:46:52:58:76:d4:6a:e6:67:1c:0e:dc:13:d0:61:72:a0:92: + cb:05:97:47:1c:c1:c9:cf:41:7d:1f:b1:4d:93:6b:53:41:03: + 21:2b:93:15:63:08:3e:2c:86:9e:7b:9f:3a:09:05:6a:7d:bb: + 1c:a7:b7:af:96:08:cb:5b:df:07:fb:9c:f2:95:11:c0:82:81: + f6:1b:bf:5a:1e:58:cd:28:ca:7d:04:eb:aa:e9:29:c4:82:51: + 2c:89:61:95:b6:ed:a5:86:7c:7c:48:1d:ec:54:96:47:79:ea: + fc:7f:f5:10:43:0a:9b:00:ef:8a:77:2e:f4:36:66:d2:6a:a6: + 95:b6:9f:23:3b:12:e2:89:d5:a4:c1:2c:91:4e:cb:94:e8:3f: + 22:0e:21:f9:b8:4a:81:5c:4c:63:ae:3d:05:b2:5c:5c:54:a7: + 55:8f:98:25:55:c4:a6:90:bc:19:29:b1:14:d4:e2:b0:95:e4: + ff:89:71:61:be:8a:16:85 +-----BEGIN CERTIFICATE----- +MIIGJzCCBA+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjELMAkGA1UEBhMCRlIx +DzANBgNVBAgMBkFsc2FjZTETMBEGA1UEBwwKU3RyYXNib3VyZzEYMBYGA1UECgwP +d3d3LmZyZWVsYW4ub3JnMRAwDgYDVQQLDAdmcmVlbGFuMS0wKwYDVQQDDCRGcmVl +bGFuIFNhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIjAgBgkqhkiG9w0BCQEW +E2NvbnRhY3RAZnJlZWxhbi5vcmcwHhcNMTIwNDI3MTAzMTE4WhcNMjIwNDI1MTAz +MTE4WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGQWxzYWNlMRgwFgYDVQQKDA93 +d3cuZnJlZWxhbi5vcmcxEDAOBgNVBAsMB2ZyZWVsYW4xDjAMBgNVBAMMBWFsaWNl +MSIwIAYJKoZIhvcNAQkBFhNjb250YWN0QGZyZWVsYW4ub3JnMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEA3W29+ID6194bH6ejLrIC4hb2Ugo8v6ZC+Mrc +k2dNYMNPjcOKABvxxEtBamnSaeU/IY7FC/giN622LEtV/3oDcrua0+yWuVafyxmZ +yTKUb4/GUgafRQPf/eiX9urWurtIK7XgNGFNUjYPq4dSJQPPhwCHE/LKAykWnZBX +RrX0Dq4XyApNku0IpjIjEXH+8ixE12wH8wt7DEvdO7T3N3CfUbaITl1qBX+Nm2Z6 +q4Ag/u5rl8NJfXg71ZmXA3XOj7zFvpyapRIZcPmkvZYn7SMCp8dXyXHPdpSiIWL2 +uB3KiO4JrUYvt2GzLBUThp+lNSZaZ/Q3yOaAAUkOx+1h08285Pi+P8lO+H2Xic4S +vMq1xtLg2bNoPC5KnbRfuFPuUD2/3dSiiragJ6uYDLOyWJDivKGt/72OVTEPAL9o +6T2pGZrwbQuiFGrGTMZOvWMSpQtNl+tCCXlT4mWqJDRwuMGrI4DnnGzt3IKqNwS4 +Qyo9KqjMIPwnXZAmWPm3FOKe4sFwc5fpawKO01JZewDsYTDxVj+cwXwFxbE2yBiF +z2FAHwfopwaH35p3C6lkcgP2k/zgAlnBluzACUI+MKJ/G0gv/uAhj1OHJQ3L6kn1 +SpvQ41/ueBjlunExqQSYD7GtZ1Kg8uOcq2r+WISE3Qc9MpQFFkUVllmgWGwYDuN3 +Zsez95kCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT +TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFlfyRO6G8y5qEFKikl5 +ajb2fT7XMB8GA1UdIwQYMBaAFCNsLT0+KV14uGw+quK7Lh5sh/JTMA0GCSqGSIb3 +DQEBBQUAA4ICAQAT5wJFPqervbja5+90iKxi1d0QVtVGB+z6aoAMuWK+qgi0vgvr +mu9ot2lvTSCSnRhjeiP0SIdqFMORmBtOCFk/kYDp9M/91b+vS+S9eAlxrNCB5VOf +PqxEPp/wv1rBcE4GBO/c6HcFon3F+oBYCsUQbZDKSSZxhDm3mj7pb67FNbZbJIzJ +70HDsRe2O04oiTx+h6g6pW3cOQMgIAvFgKN5Ex727K4230B0NIdGkzuj4KSML0NM +slSAcXZ41OoSKNjy44BVEZv0ZdxTDrRM4EwJtNyggFzmtTuV02nkUj1bYYYC5f0L +ADr6s0XMyaNk8twlWYlYDZ5uKDpVRVBfiGcq0uJIzIvemhuTrofh8pBQQNkPRDFT +Rq1iTo1Ihhl3/Fl1kXk1WR3jTjNb4jHX7lIoXwpwp767HAPKGhjQ9cFbnHMEtkro +RlJYdtRq5mccDtwT0GFyoJLLBZdHHMHJz0F9H7FNk2tTQQMhK5MVYwg+LIaee586 +CQVqfbscp7evlgjLW98H+5zylRHAgoH2G79aHljNKMp9BOuq6SnEglEsiWGVtu2l +hnx8SB3sVJZHeer8f/UQQwqbAO+Kdy70NmbSaqaVtp8jOxLiidWkwSyRTsuU6D8i +DiH5uEqBXExjrj0FslxcVKdVj5glVcSmkLwZKbEU1OKwleT/iXFhvooWhQ== +-----END CERTIFICATE----- diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationToken.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationToken.java index 02967d7f38782a1ac0e7a02e9383ea9dbc7879d5..f7b7bc016a500ce16237bd38b97b500804772592 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationToken.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationToken.java @@ -1,12 +1,15 @@ package eu.europa.ec.edelivery.smp.auth; import eu.europa.ec.edelivery.smp.data.model.DBUser; +import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import java.util.Collection; +import java.util.Objects; public class SMPAuthenticationToken extends UsernamePasswordAuthenticationToken { + DBUser user; public SMPAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { @@ -21,4 +24,20 @@ public class SMPAuthenticationToken extends UsernamePasswordAuthenticationToken public DBUser getUser() { return user; } -} + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AbstractAuthenticationToken)) return false; + if (!super.equals(o)) return false; + SMPAuthenticationToken that = (SMPAuthenticationToken) o; + // also check super equals (roles..) which is implemented in AbstractAuthenticationToken + return Objects.equals(user, that.user) && super.equals(that); + } + + @Override + public int hashCode() { + + return Objects.hash(super.hashCode(), user); + } +} \ No newline at end of file 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 1ff2692b28fad23d514465e535db0b1e8cc068e3..f819d3b3fa312e23d9ceb2618de5553ca975f1e1 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 @@ -12,6 +12,7 @@ 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.UIUserService; +import eu.europa.ec.edelivery.smp.services.ui.filters.UserFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; import org.springframework.security.core.Authentication; @@ -47,15 +48,21 @@ public class UserResource { @ResponseBody @RequestMapping(method = RequestMethod.GET) //update gui to call this when somebody is logged in. - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SERVICE_GROUP_ADMIN}) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) public ServiceResult<UserRO> getUsers( @RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, @RequestParam(value = "orderBy", required = false) String orderBy, @RequestParam(value = "orderType", defaultValue = "asc", required = false) String orderType, - @RequestParam(value = "user", required = false) String user + @RequestParam(value = "roles", required = false) String roleList ) { - return uiUserService.getTableList(page,pageSize, orderBy, orderType, null); + UserFilter filter =null; + if (roleList!=null){ + filter = new UserFilter(); + filter.setRoleList(Arrays.asList(roleList.split(","))); + } + + return uiUserService.getTableList(page,pageSize, orderBy, orderType, filter); } @PutMapping(produces = {"application/json"}) diff --git a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl index 4a4cb9e40467fbc89051d86b15c3552735e8082e..ce1c1ec0ba5f4bcfc08ebd0990d4762764024263 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl @@ -33,7 +33,7 @@ DOMAIN_CODE varchar(256) CHARACTER SET utf8 COLLATE utf8_bin not null, LAST_UPDATED_ON datetime not null, SIGNATURE_KEY_ALIAS varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, - SML_CLIENT_CERT_HEADER varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, + SML_CLIENT_CERT_HEADER varchar(4000) CHARACTER SET utf8 COLLATE utf8_bin, SML_CLIENT_KEY_ALIAS varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, SML_PARTC_IDENT_REGEXP varchar(4000) CHARACTER SET utf8 COLLATE utf8_bin, SML_SMP_ID varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, @@ -49,7 +49,7 @@ DOMAIN_CODE varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, LAST_UPDATED_ON datetime, SIGNATURE_KEY_ALIAS varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, - SML_CLIENT_CERT_HEADER varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, + SML_CLIENT_CERT_HEADER varchar(4000) CHARACTER SET utf8 COLLATE utf8_bin, SML_CLIENT_KEY_ALIAS varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, SML_PARTC_IDENT_REGEXP varchar(4000) CHARACTER SET utf8 COLLATE utf8_bin, SML_SMP_ID varchar(256) CHARACTER SET utf8 COLLATE utf8_bin, diff --git a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl index 81a43ce87078d5a6d272341dcff22e07836c2ce1..89868bbda8b0fa24e7858b79fc71cad069633581 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl @@ -39,7 +39,7 @@ create sequence SMP_USER_SEQ start with 1 increment by 50; DOMAIN_CODE varchar2(256 char) not null, LAST_UPDATED_ON timestamp not null, SIGNATURE_KEY_ALIAS varchar2(256 char), - SML_CLIENT_CERT_HEADER varchar2(256 char), + SML_CLIENT_CERT_HEADER varchar2(4000 char), SML_CLIENT_KEY_ALIAS varchar2(256 char), SML_PARTC_IDENT_REGEXP varchar2(4000 char), SML_SMP_ID varchar2(256 char), @@ -55,7 +55,7 @@ create sequence SMP_USER_SEQ start with 1 increment by 50; DOMAIN_CODE varchar2(256 char), LAST_UPDATED_ON timestamp, SIGNATURE_KEY_ALIAS varchar2(256 char), - SML_CLIENT_CERT_HEADER varchar2(256 char), + SML_CLIENT_CERT_HEADER varchar2(4000 char), SML_CLIENT_KEY_ALIAS varchar2(256 char), SML_PARTC_IDENT_REGEXP varchar2(4000 char), SML_SMP_ID varchar2(256 char),