Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS will be completely phased out by mid-2025. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit fe720c3f authored by Sebastian-Ion TINCU's avatar Sebastian-Ion TINCU
Browse files

Merge pull request #115 in EDELIVERY/smp from...

Merge pull request #115 in EDELIVERY/smp from feature/EDELIVERY-3687-smp-ui-add-edit-user to development

* commit '7d364b802ed6d9b17525355c624d739873a2072d':
  EDELIVERY-3687 SMP UI Add/Edit user
  EDELIVERY-3687 SMP UI Add/Edit user
  EDELIVERY-3687 SMP UI Add/Edit user
  EDELIVERY-3687 SMP UI Add/Edit user
parents 61da0464 139df850
No related branches found
No related tags found
No related merge requests found
Showing
with 196 additions and 258 deletions
......@@ -69,7 +69,6 @@ import {DomainDetailsDialogComponent} from './domain/domain-details-dialog/domai
import {UserDetailsDialogComponent} from './user/user-details-dialog/user-details-dialog.component';
import {DownloadService} from './download/download.service';
import {UserService} from './user/user.service';
import {RoleService} from './security/role.service';
import {CertificateService} from './user/certificate.service';
@NgModule({
......@@ -150,7 +149,7 @@ import {CertificateService} from './user/certificate.service';
DownloadService,
UserService,
CertificateService,
RoleService,
DatePipe,
{
provide: ExtendedHttpClient,
useFactory: extendedHttpClientCreator,
......
......@@ -188,7 +188,6 @@ export class SearchTableComponent implements OnInit {
}
changePageSize(newPageLimit: number) {
alert("new page size");
this.page(0, newPageLimit, this.orderBy, this.asc);
}
......
......@@ -4,7 +4,6 @@ import {UserRo} from "../../user/user-ro.model";
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
import {DomainRo} from "../domain-ro.model";
import {AlertService} from "../../alert/alert.service";
import {RoleService} from "../../security/role.service";
import {UserDetailsDialogComponent} from "../../user/user-details-dialog/user-details-dialog.component";
import {CertificateService} from "../../user/certificate.service";
import {UserService} from "../../user/user.service";
......
......@@ -5,7 +5,7 @@
<tr>
<td>
<mat-form-field>
<input matInput placeholder="Username" name="userName" [(ngModel)]="model.userName" #userName="ngModel"
<input matInput placeholder="Username" name="username" [(ngModel)]="model.username" #username="ngModel"
required id="username_id">
</mat-form-field>
</td>
......
......@@ -2,13 +2,13 @@ export enum Role {
/**
* The system administrator (a.k.a. the "super admin") role
*/
SYSTEM_ADMINISTRATOR,
SYSTEM_ADMINISTRATOR = 'System Administrator',
/**
* The SMP Administrator role. It is assimilable to the {@link SERVICE_GROUP_ADMINISTRATOR} role for now.
*/
SMP_ADMINISTRATOR,
SMP_ADMINISTRATOR = 'SMP Administrator',
/**
* The ServiceGroup administrator role
*/
SERVICE_GROUP_ADMINISTRATOR,
SERVICE_GROUP_ADMINISTRATOR = 'ServiceGroup Administrator',
}
import {Injectable} from '@angular/core';
import {Role} from './role.model';
@Injectable()
export class RoleService {
/**
* Returns a user representation of the role or an empty string if the role is unknown.
*
* @param role the role for which we need to display the user representation
*/
public getLabel(role: Role): string {
switch (role) {
case Role.SMP_ADMINISTRATOR:
return 'SMP Administrator';
case Role.SERVICE_GROUP_ADMINISTRATOR:
return 'ServiceGroup Administrator';
case Role.SYSTEM_ADMINISTRATOR:
return 'System Administrator';
default:
return '';
}
}
}
......@@ -4,4 +4,6 @@ export class SmpConstants {
public static readonly REST_USER = 'rest/user';
public static readonly REST_SEARCH = 'rest/search';
public static readonly REST_EDIT = 'rest/servicegroup';
public static readonly REST_CERTIFICATE = `${SmpConstants.REST_USER}/certdata`;
}
......@@ -2,7 +2,7 @@ export interface CertificateRo {
certificateId: string;
subject: string;
validFrom: Date;
validUntil: Date;
validTo: Date;
issuer: string;
serialNumber: string;
fingerprints: string;
......
......@@ -2,20 +2,14 @@ import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {CertificateRo} from './certificate-ro.model';
import {HttpClient} from '@angular/common/http';
import {SmpConstants} from "../smp.constants";
@Injectable()
export class CertificateService {
constructor(private http: HttpClient) {}
uploadCertificate$(payload, username: string): Observable<CertificateRo> {
return this.http.put<CertificateRo>(`rest/user/${username}/certificate`, payload);
}
onUpload(file) {
return this.http.post<CertificateRo>('rest/user/certdata',file, )
uploadCertificate$(payload): Observable<CertificateRo> {
return this.http.post<CertificateRo>(SmpConstants.REST_CERTIFICATE, payload);
}
}
......@@ -3,21 +3,24 @@
}
.custom-file-upload {
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
background-color: #2196f3;
}
.custom-file-upload-inner {
color: white;
cursor: pointer;
background-color: #2196f3;
.username, .role, .password, .password-confirmation, .certificate-subject, .certificate-issuer, .certificate-serial-number {
width: 100%;
}
.certificate-valid-from, .certificate-valid-to {
width: 40%;
}
.required-fields {
text-align: right;
font-size: 70%
}
.custom-file-upload[disabled] {
color: red;
cursor: not-allowed;
background-color: grey;
.has-error {
color:red;
font-size: 70%;
}
<h2 mat-dialog-title>{{formTitle}}</h2>
<mat-dialog-content>
<!--<table>-->
<!--<tr>-->
<!--<td width="50%" valign="top">-->
<!--<mat-grid-list cols="2" gutterSize="40px">-->
<!--<mat-grid-tile class="panel">-->
<mat-card>
<mat-card-content>
<mat-slide-toggle mat-no-ink class="mat-primary" ngModel="userSwitch">
User Details
</mat-slide-toggle>
<div class="panel">
<div style="margin-top:15px;">
<mat-form-field style="width:100%">
<input matInput placeholder="Username" name="username" id="username" [value]="current.username" (blur)="updateUserName($event)" [formControl]="userForm.controls['username']" maxlength="255" required>
<div *ngIf="userForm.controls['username'].hasError('required') && userForm.controls['username'].touched" style="color:red; font-size: 70%">You should type an username</div>
</mat-form-field>
</div>
<mat-card>
<mat-card-content>
<mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['userToggle']" (change)="onUserToggleChanged($event)">
User Details
</mat-slide-toggle>
<div *ngIf="userForm.errors?.userDetailsOrCertificateRequired && (userForm.get('userToggle').dirty || userForm.get('certificateToggle').dirty)" class="has-error">You need to enter at least the details or the certificate for this user</div>
<div style="margin-top:10px;">
<mat-select matInput placeholder="Role" [style.width]="'100%'" [formControl]="userForm.controls['role']"
[(ngModel)]="role" required>
<mat-option *ngFor="let item of existingRoles" [value]="item">{{getRoleLabel(item)}}</mat-option>
</mat-select>
<div *ngIf="userForm.controls['role'].hasError('required') && userForm.controls['role'].touched" style="color:red; font-size: 70%">You need to choose at least one role for this user</div>
</div>
<div class="panel">
<mat-form-field class="username">
<input matInput placeholder="Username" [formControl]="userForm.controls['username']" maxlength="255" required>
<div *ngIf="userForm.controls['username'].hasError('required') && userForm.controls['username'].touched" class="has-error">You should type an username</div>
</mat-form-field>
<div style="margin-top:15px;">
<mat-form-field [style.width]="'100%'">
<input matInput placeholder="Password" name="password" type="password" [value]="current.password" (blur)="updatePassword($event)" [formControl]="userForm.controls['password']" [pattern]="passwordPattern" [required]="!editMode">
<div *ngIf="!editMode && userForm.controls['password'].hasError('required') && userForm.controls['password'].touched" style="color:red; font-size: 70%">You should type a password</div>
<div *ngIf="userForm.controls['password'].dirty && userForm.controls['password'].hasError('pattern') && userForm.controls['password'].touched" style="color:red; font-size: 70%">
Password should follow all of these rules:<br>
- Minimum length: 8 characters<br>
- Maximum length: 32 characters<br>
- At least one letter in lowercase<br>
- At least one letter in uppercase<br>
- At least one digit<br>
- At least one special character
</div>
</mat-form-field>
</div>
<mat-form-field class="role">
<mat-select matInput placeholder="Role" class="role" [formControl]="userForm.controls['role']" required>
<mat-option *ngFor="let item of existingRoles" [value]="item">{{item}}</mat-option>
</mat-select>
<div *ngIf="userForm.controls['role'].hasError('required') && userForm.controls['role'].touched" class="has-error">You need to choose at least one role for this user</div>
</mat-form-field>
<div>
<mat-form-field [style.width]="'100%'">
<input matInput placeholder="Confirmation" name="confirmation" type="password" [value]="current.confirmation" [formControl]="userForm.controls['confirmation']" [required]="!editMode">
<div *ngIf="!editMode && userForm.controls['confirmation'].hasError('required') && userForm.controls['confirmation'].touched" style="color:red; font-size: 70%">You should type a password</div>
<div *ngIf="userForm.errors?.confirmation && userForm.controls['confirmation'].touched" style="color:red; font-size: 70%">Passwords do not match</div>
</mat-form-field>
</div>
<mat-form-field class="password">
<input matInput placeholder="Password" type="password" [formControl]="userForm.controls['password']" [pattern]="passwordPattern" [required]="!editMode">
<div *ngIf="!editMode && userForm.controls['password'].hasError('required') && userForm.controls['password'].touched" class="has-error">You should type a password</div>
<div *ngIf="userForm.controls['password'].dirty && userForm.controls['password'].hasError('pattern') && userForm.controls['password'].touched" class="has-error">
Password should follow all of these rules:<br>
- Minimum length: 8 characters<br>
- Maximum length: 32 characters<br>
- At least one letter in lowercase<br>
- At least one letter in uppercase<br>
- At least one digit<br>
- At least one special character
</div>
</mat-card-content>
</mat-card>
<!--</mat-grid-tile>-->
<!--</td>-->
</mat-form-field>
<!--<td width="50%" valign="top">-->
<!--<mat-grid-tile class="panel">-->
<mat-card>
<mat-card-content>
<mat-slide-toggle mat-no-ink class="mat-primary" ngModel="certificateSwitch">
Certificate
</mat-slide-toggle>
<div class="panel">
<fieldset [disabled]="true" style="border: none;">
<mat-form-field style="width:100%">
<input matInput placeholder="Subject Name" name="subjectName" value="{{current.certificate?.subject}}" id="subjectName_id">
</mat-form-field>
<mat-form-field style="width:40%">
<input matInput placeholder="Valid From" name="validityFrom" value="{{current.certificate?.validFrom | smpDate: dateFormat}}" id="validityFrom_id">
</mat-form-field>
<mat-form-field style="width:40%">
<input matInput placeholder="Valid To" name="validityTo" value="{{current.certificate?.validUntil | smpDate: dateFormat}}" id="validityTo_id">
</mat-form-field>
<mat-form-field style="width:100%">
<input matInput placeholder="Issuer" name="issuer" value="{{current.certificate?.issuer}}" id="issuer_id">
</mat-form-field>
<mat-form-field style="width:100%">
<input matInput placeholder="Fingerprints" name="fingerPrint" value="{{current.certificate?.fingerprints}}" id="fingerPrint_id">
</mat-form-field>
</fieldset>
<mat-form-field class="password-confirmation">
<input matInput placeholder="Confirmation" type="password" [formControl]="userForm.controls['confirmation']" [required]="!editMode">
<div *ngIf="!editMode && userForm.controls['confirmation'].hasError('required') && userForm.controls['confirmation'].touched" class="has-error">You should type a password</div>
<div *ngIf="userForm.errors?.confirmationMatch && userForm.controls['confirmation'].touched" class="has-error">Passwords do not match</div>
</mat-form-field>
</div>
<input
type="file" (change)="onFileChanged($event)"
#fileInput>
<button (click)="onUpload()">Upload!</button>
<mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['certificateToggle']">
Certificate
</mat-slide-toggle>
<div *ngIf="userForm.errors?.userDetailsOrCertificateRequired && (userForm.get('userToggle').dirty || userForm.get('certificateToggle').dirty)" class="has-error">You need to enter at least the details or the certificate for this user</div>
<div *ngIf="userForm.errors?.certificateDetailsRequired && userForm.get('certificateToggle').touched" class="has-error">All the certificate fields are required so please upload a new certificate</div>
<div class="panel">
<mat-form-field class="certificate-subject">
<input matInput placeholder="Subject Name" [formControl]="userForm.controls['subject']">
</mat-form-field>
<mat-form-field class="certificate-valid-from">
<input matInput placeholder="Valid From" [formControl]="userForm.controls['validFrom']">
</mat-form-field>
<mat-form-field class="certificate-valid-to">
<input matInput placeholder="Valid To" [formControl]="userForm.controls['validTo']">
</mat-form-field>
<mat-form-field class="certificate-issuer">
<input matInput placeholder="Issuer" [formControl]="userForm.controls['issuer']">
</mat-form-field>
<mat-form-field class="certificate-serial-number">
<input matInput placeholder="Serial Number" [formControl]="userForm.controls['serialNumber']">
</mat-form-field>
<label class="custom-file-upload">
<input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" [disabled]="!certificateSwitch">
<span class="custom-file-upload-inner">Import</span>
</label>
</div>
</mat-card-content>
</mat-card>
<!--</mat-grid-tile>-->
<!--</mat-grid-list>-->
<!--</td>-->
<!--</tr>-->
<!--</table>-->
<label class="custom-file-upload">
<input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate($event)" [disabled]="!userForm.controls['certificateToggle']?.value">
<button mat-flat-button color="primary" (click)="fileInput.click()" [disabled]="!userForm.controls['certificateToggle']?.value">Import</button>
</label>
</div>
</mat-card-content>
</mat-card>
</mat-dialog-content>
<table class="buttonsRow">
......@@ -115,5 +87,5 @@
</td>
</tr>
</table>
<div style="text-align: right; font-size: 70%">* required fields</div>
<div class="required-fields">* required fields</div>
import {Component, Inject, ViewChild} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import {AbstractControl, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms';
import {MAT_DIALOG_DATA, MatDialogRef, MatSlideToggleChange} from '@angular/material';
import {FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms';
import {UserService} from '../user.service';
import {Role} from '../../security/role.model';
import {RoleService} from '../../security/role.service';
import {UserRo} from '../user-ro.model';
import {SearchTableEntityStatus} from '../../common/search-table/search-table-entity-status.model';
import {AlertService} from '../../alert/alert.service';
import {CertificateService} from '../certificate.service';
import {Observable} from "rxjs/index";
import {CertificateRo} from "../certificate-ro.model";
import {SearchTableResult} from "../../common/search-table/search-table-result.model";
import {DatePipe} from "../../custom-date/date.pipe";
@Component({
selector: 'user-details-dialog',
......@@ -25,47 +22,64 @@ 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';
editMode: boolean;
formTitle: string;
userRoles = [];
role: string; // temporally added by JRC just to compile the code
dateFormat: string; // temporally added by JRC just to compile the code
existingRoles = [];
current: UserRo & { confirmation?: string };
userForm: FormGroup;
userSwitch: boolean;
certificateSwitch: boolean;
@ViewChild('fileInput')
private fileInput;
private passwordConfirmationValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const userToggle = control.get('userToggle');
const password = control.get('password');
const confirmation = control.get('confirmation');
return password && confirmation && password.value !== confirmation.value ? { confirmation: true } : null;
return userToggle && password && confirmation && userToggle.value && password.value !== confirmation.value ? { confirmationMatch: true } : null;
};
private atLeastOneToggleCheckedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const userToggle = control.get('userToggle');
const certificateToggle = control.get('certificateToggle');
return userToggle && certificateToggle && !userToggle.value && !certificateToggle.value ? { userDetailsOrCertificateRequired: true} : null;
};
private certificateValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const certificateToggle = control.get('certificateToggle');
const subject = control.get('subject');
const validFrom = control.get('validFrom');
const validTo = control.get('validTo');
const issuer = control.get('issuer');
const serialNumber = control.get('serialNumber');
return certificateToggle && subject && validFrom && validTo && issuer && serialNumber
&& certificateToggle.value && !(subject.value && validFrom.value && validTo.value && issuer.value && serialNumber.value) ? { certificateDetailsRequired: true} : null;
};
constructor(private dialogRef: MatDialogRef<UserDetailsDialogComponent>,
private userService: UserService,
private certificateService: CertificateService,
private alertService: AlertService,
private roleService: RoleService,
private datePipe: DatePipe,
@Inject(MAT_DIALOG_DATA) public data: any,
private fb: FormBuilder) {
this.editMode = data.edit;
this.formTitle = this.editMode ? UserDetailsDialogComponent.EDIT_MODE: UserDetailsDialogComponent.NEW_MODE;
this.current = this.editMode
const user: UserRo & { confirmation?: string } = this.editMode
? {
...data.row,
confirmation: data.row.password,
certificate: data.row.certificate,
}
: {
password: '', // ensures the user password is cleared before editing
confirmation: '',
certificate: {
subject: data.row.subject,
validFrom: data.row.validFrom,
validTo: data.row.validTo,
issuer: data.row.issuer,
serialNumber: data.row.serialNumber,
}
}: {
username: '',
email: '',
password: '',
......@@ -75,17 +89,29 @@ export class UserDetailsDialogComponent {
certificate: {},
};
const userDetailsToggled: boolean = user && !!user.username;
this.userForm = fb.group({
'username': new FormControl({value: this.current.username, disabled: this.editMode}, this.editMode ? Validators.nullValidator : null),
'role': new FormControl(this.current.role, Validators.required),
'password': new FormControl(this.current.password, [Validators.required, Validators.pattern(this.passwordPattern)]),
'confirmation': new FormControl(this.current.password, Validators.pattern(this.passwordPattern)), }, { validator: this.passwordConfirmationValidator
'userToggle': new FormControl(userDetailsToggled),
'username': new FormControl({ value: user.username, disabled: this.editMode || !userDetailsToggled }, this.editMode ? Validators.nullValidator : null),
'role': new FormControl({ value: user.role, disabled: !userDetailsToggled }, Validators.required),
'password': new FormControl({ value: user.password, disabled: !userDetailsToggled }, [Validators.required, Validators.pattern(this.passwordPattern)]),
'confirmation': new FormControl({ value: user.password, disabled: !userDetailsToggled }, Validators.pattern(this.passwordPattern)),
'certificateToggle': new FormControl(user && user.certificate && !!user.certificate.subject),
'subject': new FormControl({ value: user.certificate.subject, disabled: true }, Validators.required),
'validFrom': new FormControl({ value: user.certificate.validFrom, disabled: true }, Validators.required),
'validTo': new FormControl({ value: user.certificate.validTo, disabled: true }, Validators.required),
'issuer': new FormControl({ value: user.certificate.issuer, disabled: true }, Validators.required),
'serialNumber': new FormControl({ value: user.certificate.serialNumber, disabled: true }, Validators.required),
}, {
validator: [this.passwordConfirmationValidator, this.atLeastOneToggleCheckedValidator, this.certificateValidator]
});
this.userService.getUserRoles$().subscribe(userRoles => {
this.userRoles = userRoles.json();
this.existingRoles = this.editMode
? this.getAllowedRoles(this.userRoles, this.current.role)
? this.getAllowedRoles(this.userRoles, user.role)
: this.userRoles;
});
}
......@@ -94,41 +120,19 @@ export class UserDetailsDialogComponent {
this.dialogRef.close(true);
}
updateUserName(event) {
this.current.username = event.target.value;
}
updatePassword(event) {
this.current.password = event.target.value;
}
getRoleLabel(role: Role): string {
return this.roleService.getLabel(role);
}
// filters out roles so that the user cannot change from system administrator to the other roles or vice-versa
private getAllowedRoles(allRoles, userRole) {
if (userRole === Role.SYSTEM_ADMINISTRATOR) {
return [Role.SYSTEM_ADMINISTRATOR];
} else {
return allRoles.filter(role => role !== Role.SYSTEM_ADMINISTRATOR);
}
}
uploadCertificate () {
const fi = this.fileInput.nativeElement;
const file = fi.files[0];
uploadCertificate(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
const arrayBuffer = reader.result;
const array = new Uint8Array(arrayBuffer);
const binaryString = String.fromCharCode.apply(null, array);
// TODO define userName or use some sort of userId
this.certificateService.uploadCertificate$({content: binaryString}, 'TODO')
.subscribe(res => {
this.current.certificate = res;
this.certificateService.uploadCertificate$(reader.result).subscribe((res: CertificateRo) => {
this.userForm.patchValue({
'subject': res.subject,
'validFrom': this.datePipe.transform(res.validFrom.toString(), this.dateFormat),
'validTo': this.datePipe.transform(res.validTo.toString(), this.dateFormat),
'issuer': res.issuer,
'serialNumber': res.serialNumber
});
},
err => {
this.alertService.exception('Error uploading certificate file ' + file.name, err);
......@@ -139,23 +143,27 @@ export class UserDetailsDialogComponent {
this.alertService.exception('Error reading certificate file ' + file.name, err);
};
reader.readAsArrayBuffer(file);
reader.readAsBinaryString(file);
}
// example
selectedFile: File;
obrs: Observable< CertificateRo> ;
certData: CertificateRo;
onFileChanged(event) {
this.selectedFile = event.target.files[0]
onUserToggleChanged({checked}: MatSlideToggleChange) {
const action = checked ? 'enable' : 'disable';
this.userForm.get('username')[action]();
this.userForm.get('role')[action]();
this.userForm.get('password')[action]();
this.userForm.get('confirmation')[action]();
}
onUpload() {
this.obrs = this.certificateService.onUpload(this.selectedFile);
this.obrs.subscribe((cert: CertificateRo) => {
this.certData = cert;
});
get current(): UserRo {
return this.userForm.getRawValue();
}
// filters out roles so that the user cannot change from system administrator to the other roles or vice-versa
private getAllowedRoles(allRoles, userRole) {
if (userRole === Role.SYSTEM_ADMINISTRATOR) {
return [Role.SYSTEM_ADMINISTRATOR];
} else {
return allRoles.filter(role => role !== Role.SYSTEM_ADMINISTRATOR);
}
}
}
<smp-search-table
page_id= 'user_id'
title= 'Users'
[columnPicker] = "columnPicker"
page_id="user_id"
title="Users"
[columnPicker]="columnPicker"
[url]="'rest/user'"
[additionalToolButtons]="additionalToolButtons"
[searchTableController]="userController"
[searchPanel]="searchPanel"
[showSearchPanel]="false"
[filter]="filter">
<ng-template #additionalToolButtons></ng-template>
<ng-template #searchPanel>
<mat-form-field>
<input matInput placeholder="Username" name="Username" [(ngModel)]="filter.username" #messageId="ngModel">
</mat-form-field>
</ng-template>
</smp-search-table>
......@@ -31,22 +31,20 @@ export class UserComponent implements OnInit {
prop: 'username',
canAutoResize: true
},
{
name: 'Certificate',
prop: 'subject',
canAutoResize: true
},
{
name: 'Role',
prop: 'role',
canAutoResize: true
},
{
name: 'Password',
prop: 'password',
canAutoResize: true,
sortable: false,
width: 25
}
];
this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
return ['Username', 'Role'].indexOf(col.name) != -1
return ['Username', 'Certificate', 'Role'].indexOf(col.name) != -1
});
}
......
......@@ -451,6 +451,11 @@
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- End Jackson-->
<dependency>
<groupId>org.apache.commons</groupId>
......@@ -676,7 +681,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- fork needs to be false to compile JAXB resources. Otherwise the
<!-- fork needs to be false to compile JAXB resources. Otherwise the
problem with the forward slash in package-info.java on Windows occurs! -->
<fork>false</fork>
<source>1.8</source>
......
......@@ -112,6 +112,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
......
package eu.europa.ec.edelivery.smp.data.ui;
import eu.europa.ec.edelivery.smp.data.model.CommonColumnsLengths;
import javax.persistence.Column;
import javax.persistence.Id;
import java.math.BigInteger;
import java.time.LocalDateTime;
/**
* @author Joze Rihtarsic
* @since 4.1
*/
public class CertificateRO extends BaseRO {
private static final long serialVersionUID = -4971552086560325302L;
private String certificateId;
......@@ -30,7 +18,6 @@ public class CertificateRO extends BaseRO {
private LocalDateTime validTo;
public CertificateRO(){
}
public static long getSerialVersionUID() {
......
......@@ -23,7 +23,8 @@ public enum ErrorCode {
ILLEGAL_STATE_CERT_ID_MULTIPLE_ENTRY(504,"SMP:122",ErrorBusinessCode.TECHNICAL,"More than one certificate entry (cert. id: '%s') is defined in database!"),
USER_NOT_EXISTS(400,"SMP:123",ErrorBusinessCode.USER_NOT_FOUND,"User not exists or wrong password!"), // OWASP recommendation\
USER_IS_NOT_OWNER(400,"SMP:124",ErrorBusinessCode.UNAUTHORIZED,"User %s is not owner of service group (part. id: %s, part. sch.: '%s')!"), // OWASP recommendation
INVALID_CERTIFICATE_MESSAGE_DIGEST(500, "SMP:125", ErrorBusinessCode.TECHNICAL, "Could not initialize MessageDigest"),
INVALID_CERTIFICATE_ENCODING(500, "SMP:126", ErrorBusinessCode.TECHNICAL, "Could not encode certificate"),
// service group error
ILLEGAL_STATE_SG_MULTIPLE_ENTRY (500,"SMP:130",ErrorBusinessCode.TECHNICAL,"More than one service group ( part. id: %s, part. sch.: '%s') is defined in database!"),
......
......@@ -5,16 +5,15 @@ import eu.europa.ec.edelivery.smp.BCryptPasswordHash;
import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
import eu.europa.ec.edelivery.smp.data.dao.UserDao;
import eu.europa.ec.edelivery.smp.data.model.DBCertificate;
import eu.europa.ec.edelivery.smp.data.model.DBDomain;
import eu.europa.ec.edelivery.smp.data.model.DBUser;
import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
import eu.europa.ec.edelivery.smp.data.ui.UserRO;
import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
import eu.europa.ec.edelivery.smp.exceptions.ErrorCode;
import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
import eu.europa.ec.edelivery.smp.logging.SMPLogger;
import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
import eu.europa.ec.edelivery.smp.services.ServiceGroupService;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -22,15 +21,16 @@ import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.ejb.Local;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
......@@ -138,9 +138,6 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
cro.setValidTo(LocalDateTime.ofInstant(cert.getNotAfter().toInstant(), ZoneId.systemDefault()));
return cro;
}
public String getCertificateIdFromCertificate(String subject, String issuer, BigInteger serial ){
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment