From c0a2eda7d6311b87584fd5187c496a1e7dba869c Mon Sep 17 00:00:00 2001
From: RIHTARSIC Joze <joze.rihtarsic@ext.ec.europa.eu>
Date: Tue, 11 Apr 2023 20:51:35 +0200
Subject: [PATCH] Add domain member managing

---
 smp-angular/src/app/app.module.ts             |  12 ++
 .../credential-dialog.component.html          |   2 +-
 .../credential-dialog.component.ts            |   2 -
 smp-angular/src/app/common/global-lookups.ts  |   4 +-
 smp-angular/src/app/smp.constants.ts          |  32 +++-
 .../admin-domain/admin-domain.component.html  |   5 +-
 .../domain-member-panel.component.html        |  95 ++++++++++
 .../domain-member-panel.component.scss        |  20 ++
 .../domain-member-panel.component.ts          | 178 ++++++++++++++++++
 .../member-dialog/member-dialog.component.css |  13 ++
 .../member-dialog.component.html              |  46 +++++
 .../member-dialog/member-dialog.component.ts  | 138 ++++++++++++++
 .../member-dialog/member-type.enum.ts         |   8 +
 .../member-dialog/search-user-ro.model.ts     |   9 +
 .../domain-member-panel/member-ro.model.ts    |  13 ++
 .../membership-role.enum.ts                   |   7 +
 .../domain-member-panel/membership.service.ts |  71 +++++++
 .../domain-member-panel/table-result.model.ts |   8 +
 .../domain-panel/domain-panel.component.ts    |   1 +
 .../app/system-settings/user/user-ro.model.ts |   1 +
 .../user-profile/user-profile.component.html  |   4 +-
 .../DBDomainMemberToMemberROConverter.java    |  27 +++
 .../DBUserToSearchUserROConverter.java        |  24 +++
 .../smp/data/dao/DomainMemberDao.java         |  51 ++++-
 .../ec/edelivery/smp/data/dao/QueryNames.java |  11 ++
 .../ec/edelivery/smp/data/dao/UserDao.java    |  27 +++
 .../smp/data/model/user/DBDomainMember.java   |  38 +++-
 .../edelivery/smp/data/model/user/DBUser.java |  12 ++
 .../ec/edelivery/smp/data/ui/MemberRO.java    |  52 +++++
 .../edelivery/smp/data/ui/SearchUserRO.java   |  32 ++++
 .../services/ui/UIDomainPublicService.java    |  84 ++++++++-
 .../smp/services/ui/UIUserService.java        |  22 ++-
 .../smp/data/dao/DomainMemberDaoTest.java     | 101 +++++++---
 .../ui/UIUserServiceIntegrationTest.java      |   3 -
 .../mysql-4.1_integration_test_data.sql       |   4 +
 .../smp/auth/SMPAuthorizationService.java     |  27 ++-
 .../edelivery/smp/ui/ResourceConstants.java   |   1 +
 .../smp/ui/external/DomainResource.java       |  61 +++++-
 .../smp/ui/external/UserResource.java         |  12 ++
 .../smp/auth/SMPAuthorizationServiceTest.java |   4 +-
 40 files changed, 1188 insertions(+), 74 deletions(-)
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.html
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.scss
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.css
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.html
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-type.enum.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/search-user-ro.model.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-ro.model.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership.service.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-domain/domain-member-panel/table-result.model.ts
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainMemberToMemberROConverter.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToSearchUserROConverter.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/MemberRO.java
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SearchUserRO.java

diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index a0ac74f8b..dca9f8ac4 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -126,6 +126,14 @@ import {
   NGX_MAT_MOMENT_FORMATS, NgxMatMomentAdapter,
   NgxMatMomentModule
 } from "@angular-material-components/moment-adapter";
+import {
+  DomainMemberPanelComponent
+} from "./system-settings/admin-domain/domain-member-panel/domain-member-panel.component";
+import {
+  MemberDialogComponent
+} from "./system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component";
+import {MatAutocompleteModule} from "@angular/material/autocomplete";
+import {MembershipService} from "./system-settings/admin-domain/domain-member-panel/membership.service";
 
 
 @NgModule({
@@ -157,6 +165,7 @@ import {
     DomainPanelComponent,
     DomainSmlIntegrationPanelComponent,
     DomainDetailsDialogComponent,
+    DomainMemberPanelComponent,
     DomainResourceTypePanelComponent,
     DomainSelectorComponent,
     ExpiredPasswordDialogComponent,
@@ -168,6 +177,7 @@ import {
     KeystoreEditDialogComponent,
     KeystoreImportDialogComponent,
     LoginComponent,
+    MemberDialogComponent,
     NavTree,
     NavTreeMenu,
     ObjectPropertiesDialogComponent,
@@ -232,6 +242,7 @@ import {
     NgxMatMomentModule,
     ReactiveFormsModule,
     routing,
+    MatAutocompleteModule,
   ],
   providers: [
     AdminDomainService,
@@ -244,6 +255,7 @@ import {
     CertificateService,
     DatePipe,
     DomainService,
+    MembershipService,
     DownloadService,
     ExtensionService,
     GlobalLookups,
diff --git a/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.html b/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.html
index 0ef1bac35..696ae7075 100644
--- a/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.html
+++ b/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.html
@@ -7,7 +7,7 @@
     {{message}}
   </div>
 
-    <div *ngIf="!isReadOnly" class="panel" [formGroup]="credentialForm" (ngSubmit)="submitForm()">
+    <div *ngIf="!isReadOnly" class="panel" [formGroup]="credentialForm" >
 
       <mat-form-field style="width: 100%">
         <mat-label>Description</mat-label>
diff --git a/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.ts b/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.ts
index f86fc02b9..72c80a152 100644
--- a/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.ts
+++ b/smp-angular/src/app/common/dialogs/credential-dialog/credential-dialog.component.ts
@@ -152,10 +152,8 @@ export class CredentialDialogComponent {
 
   storeCertificateCredentials() {
     this.clearAlert();
-
     this.userService.storeUserCertificateCredential(this.initCredential);
     this.closeDialog();
-
   }
 
 
diff --git a/smp-angular/src/app/common/global-lookups.ts b/smp-angular/src/app/common/global-lookups.ts
index a1c3de031..50262cb1b 100644
--- a/smp-angular/src/app/common/global-lookups.ts
+++ b/smp-angular/src/app/common/global-lookups.ts
@@ -72,12 +72,12 @@ export class GlobalLookups {
   }
 
   public refreshDomainLookupFromPublic() {
-    let domainUrl = SmpConstants.REST_PUBLIC_DOMAIN_SEARCH;
+    let domainUrl = SmpConstants.REST_PUBLIC_DOMAIN_MANAGE;
     this.refreshDomainLookup(domainUrl);
   }
 
   public refreshDomainLookupForLoggedUser() {
-    let domainUrl = SmpConstants.REST_PUBLIC_DOMAIN_SEARCH;
+    let domainUrl = SmpConstants.REST_PUBLIC_DOMAIN_MANAGE;
     // for authenticated admin use internal url which returns more data!
     if (this.securityService.isCurrentUserSystemAdmin()) {
       domainUrl = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED;
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index fc490b5fe..fcddea6f7 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -10,11 +10,14 @@ export class SmpConstants {
   public static readonly PATH_ACTION_DELETE = 'delete';
   public static readonly PATH_ACTION_UPDATE = 'update';
   public static readonly PATH_ACTION_CREATE = 'create';
+
+  public static readonly PATH_ACTION_ADD = 'add';
   public static readonly PATH_ACTION_UPDATE_RESOURCE_TYPES = 'update-resource-types';
 
   public static readonly PATH_ACTION_UPDATE_SML_INTEGRATION = 'update-sml-integration-data';
   public static readonly PATH_PARAM_ENC_USER_ID = '{user-id}';
-  public static readonly PATH_PARAM_ENC_DOMAIN_ID = '{domainr-id}';
+  public static readonly PATH_PARAM_ENC_DOMAIN_ID = '{domain-id}';
+  public static readonly PATH_PARAM_ENC_MEMBER_ID = '{member-id}';
   public static readonly PATH_PARAM_CERT_ALIAS = '{cert-alias}';
   public static readonly PATH_PARAM_ENC_CREDENTIAL_ID = '{credential-id}';
   public static readonly PATH_PARAM_ENC_MANAGED_USER_ID = '{managed-user-id}';
@@ -29,14 +32,29 @@ export class SmpConstants {
   public static readonly REST_PUBLIC = 'public/rest/';
   public static readonly REST_INTERNAL = 'internal/rest/';
   public static readonly REST_PUBLIC_SEARCH_SERVICE_GROUP = SmpConstants.REST_PUBLIC + 'search';
-  public static readonly REST_PUBLIC_DOMAIN_SEARCH = SmpConstants.REST_PUBLIC + 'domain';
+  public static readonly REST_PUBLIC_DOMAIN_MANAGE = SmpConstants.REST_PUBLIC + 'domain';
+  public static readonly REST_PUBLIC_DOMAIN_MEMBERS = SmpConstants.REST_PUBLIC_DOMAIN_MANAGE
+    + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/"+ SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + "/"+ "members";
+
+  public static readonly REST_PUBLIC_DOMAIN_MEMBERS_ADD = SmpConstants.REST_PUBLIC_DOMAIN_MANAGE
+    + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/"+ SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + "/"+ "member";
+
+  public static readonly REST_PUBLIC_DOMAIN_MEMBERS_DELETE = SmpConstants.REST_PUBLIC_DOMAIN_MANAGE
+    + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/"+ SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + "/"+ "member"
+    +"/" + SmpConstants.PATH_PARAM_ENC_MEMBER_ID +"/" +  SmpConstants.PATH_ACTION_DELETE;
+
+
+
   public static readonly REST_PUBLIC_APPLICATION_INFO = SmpConstants.REST_PUBLIC + 'application/info';
   public static readonly REST_PUBLIC_APPLICATION_CONFIG = SmpConstants.REST_PUBLIC + 'application/config';
   // user public services
   public static readonly REST_PUBLIC_USER = SmpConstants.REST_PUBLIC + 'user';
+
   public static readonly REST_PUBLIC_USER_UPDATE = SmpConstants.REST_PUBLIC_USER + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/";
   public static readonly REST_PUBLIC_USER_GENERATE_ACCESS_TOKEN = SmpConstants.REST_PUBLIC_USER_UPDATE + 'generate-access-token';
   public static readonly REST_PUBLIC_USER_CHANGE_PASSWORD = SmpConstants.REST_PUBLIC_USER_UPDATE + 'change-password';
+
+  public static readonly REST_PUBLIC_USER_SEARCH = SmpConstants.REST_PUBLIC_USER + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/" + 'search'
   // truststore public services
   public static readonly REST_PUBLIC_TRUSTSTORE = SmpConstants.REST_PUBLIC + "truststore/" + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/";
   public static readonly REST_PUBLIC_TRUSTSTORE_CERT_VALIDATE = SmpConstants.REST_PUBLIC_TRUSTSTORE + 'validate-certificate';
@@ -66,21 +84,21 @@ export class SmpConstants {
     '/' + SmpConstants.PATH_PARAM_ENC_USER_ID;
 
   public static readonly REST_INTERNAL_DOMAIN_MANAGE_DELETE = SmpConstants.REST_INTERNAL + 'domain' +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID +  '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_DELETE;
+    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_DELETE;
 
   public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE = SmpConstants.REST_INTERNAL + 'domain' +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID +  '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE;
+    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE;
 
   public static readonly REST_INTERNAL_DOMAIN_MANAGE_CREATE = SmpConstants.REST_INTERNAL + 'domain' +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID +  '/' + SmpConstants.PATH_ACTION_CREATE;
+    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_ACTION_CREATE;
 
 
   public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE_SML_INTEGRATION = SmpConstants.REST_INTERNAL + 'domain' +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID +  '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_SML_INTEGRATION;
+    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_SML_INTEGRATION;
 
 
   public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE_RESOURCE_TYPES = SmpConstants.REST_INTERNAL + 'domain' +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID +  '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_RESOURCE_TYPES;
+    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_RESOURCE_TYPES;
 
   public static readonly REST_INTERNAL_EXTENSION_MANAGE = SmpConstants.REST_INTERNAL + 'extension';
   public static readonly REST_INTERNAL_PROPERTY_MANAGE = SmpConstants.REST_INTERNAL + 'property';
diff --git a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html
index 6659889fa..46d2558b7 100644
--- a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html
+++ b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html
@@ -30,7 +30,9 @@
         ></domain-sml-integration-panel>
       </mat-tab>
       <mat-tab label="Members">
-        Content 3
+        <domain-member-panel #domainMemberPanelComponent
+                             [domain]="selected"
+        ></domain-member-panel>
       </mat-tab>
     </mat-tab-group>
   </data-panel>
@@ -46,7 +48,6 @@
     <mat-toolbar-row class="mat-elevation-z5">
       <button mat-raised-button
               mat-flat-button color="primary"
-              onDiscardNew
               (click)="onCreateDomainClicked()"
               >Create domain
       </button>
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.html b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.html
new file mode 100644
index 000000000..21ab9c182
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.html
@@ -0,0 +1,95 @@
+<form [formGroup]="domainForm" >
+  <div id="domain-member-panel" class="mat-elevation-z2">
+    <mat-toolbar>
+      <mat-toolbar-row>
+        <button id="addMemberButton" mat-raised-button (click)="onAddMemberButtonClicked()" color="primary"
+                [disabled]="inviteMemberDisabled"
+        >
+          <mat-icon>people</mat-icon>
+          <span>Invite member</span>
+        </button>
+        <button id="editButton" mat-raised-button (click)="onEditSelectedButtonClicked()" color="primary"
+                [disabled]="!selectedMember">
+          <mat-icon>edit</mat-icon>
+          <span>Edit selected member</span>
+        </button>
+        <button id="deleteButton" mat-raised-button (click)="onDeleteSelectedButtonClicked()" color="primary"
+                [disabled]="!selectedMember">
+          <mat-icon>delete</mat-icon>
+          <span>Delete selected member</span>
+        </button>
+
+
+
+
+      </mat-toolbar-row>
+    </mat-toolbar>
+    <h3>Domain members</h3>
+    <div class="domain-member-container mat-elevation-z8">
+      <div class="domain-member-loading-shade"
+           *ngIf="isLoadingResults">
+        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
+      </div>
+
+      <div class="domain-member-table-container">
+
+        <mat-form-field id="domain-member-filter" >
+          <mat-label>Member filter</mat-label>
+          <input matInput (keyup)="applyMemberFilter($event)"
+                 placeholder="Member filter"
+                 [disabled]="domainNotSelected"
+          #inputDomainMemberFilter>
+        </mat-form-field>
+
+        <table  class="mat-elevation-z2"  mat-table [dataSource]="data">
+
+          <ng-container matColumnDef="username">
+            <th mat-header-cell *matHeaderCellDef>username</th>
+            <td mat-cell *matCellDef="let row">{{row.username}}</td>
+          </ng-container>
+
+          <ng-container matColumnDef="fullName">
+            <th mat-header-cell *matHeaderCellDef>fullName</th>
+            <td mat-cell *matCellDef="let row">{{row.fullName}}</td>
+          </ng-container>
+
+          <ng-container matColumnDef="roleType">
+            <th mat-header-cell *matHeaderCellDef>roleType</th>
+            <td mat-cell *matCellDef="let row">{{row.roleType}}</td>
+          </ng-container>
+
+          <ng-container matColumnDef="memberOf">
+            <th mat-header-cell *matHeaderCellDef>memberOf</th>
+            <td mat-cell *matCellDef="let row">{{row.memberOf}}</td>
+          </ng-container>
+
+
+          <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+
+
+          <tr mat-row *matRowDef="let odd = odd; let row; columns: displayedColumns;"
+              (click)="memberSelected(row)"
+              [ngClass]="{'datatable-row-selected': row==selectedMember,'datatable-row-odd': odd}"
+          ></tr>
+
+          <tr class="mat-row" *matNoDataRow>
+            <td *ngIf="inputDomainMemberFilter.value;else noDataFound" class="mat-cell" colspan="2">No direct members matching the filter
+              "{{inputDomainMemberFilter.value}}"
+            </td>
+            <ng-template #noDataFound>
+              <td class="mat-cell" colspan="2">No direct members for the domain</td>
+            </ng-template>
+          </tr>
+        </table>
+      </div>
+
+      <mat-paginator [length]="resultsLength"
+                     (page)="onPageChanged($event)"
+                     [pageSize]="5"
+                     [pageSizeOptions]="[5, 10, 25]"
+                     [disabled]="domainNotSelected"
+                     aria-label="Select pages"></mat-paginator>
+    </div>
+
+  </div>
+</form>
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.scss b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.scss
new file mode 100644
index 000000000..e4c6e7393
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.scss
@@ -0,0 +1,20 @@
+
+
+
+.domain-member-loading-shade {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 56px;
+  right: 0;
+  background: rgba(0, 0, 0, 0.15);
+  z-index: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+#domain-member-filter {
+  width: 100%;
+  padding-top: 1em;
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.ts
new file mode 100644
index 000000000..77ed57a39
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/domain-member-panel.component.ts
@@ -0,0 +1,178 @@
+import {Component, EventEmitter, Input, Output, ViewChild,} from '@angular/core';
+import {DomainRo} from "../domain-ro.model";
+import {FormBuilder, FormControl, FormGroup} from "@angular/forms";
+import {AdminDomainService} from "../admin-domain.service";
+import {AlertMessageService} from "../../../common/alert-message/alert-message.service";
+import {MatDialog} from "@angular/material/dialog";
+import {BeforeLeaveGuard} from "../../../window/sidenav/navigation-on-leave-guard";
+import {MatPaginator, PageEvent} from "@angular/material/paginator";
+import {MemberRo} from "./member-ro.model";
+import {finalize} from "rxjs/operators";
+import {TableResult} from "./table-result.model";
+import {MemberDialogComponent} from "./member-dialog/member-dialog.component";
+import {MembershipService} from "./membership.service";
+import {MembershipRoleEnum} from "./membership-role.enum";
+import {MemberTypeEnum} from "./member-dialog/member-type.enum";
+
+
+@Component({
+  selector: 'domain-member-panel',
+  templateUrl: './domain-member-panel.component.html',
+  styleUrls: ['./domain-member-panel.component.scss']
+})
+export class DomainMemberPanelComponent implements BeforeLeaveGuard {
+  @Output() onSaveSmlIntegrationDataEvent: EventEmitter<DomainRo> = new EventEmitter();
+  private _domain: DomainRo;
+
+
+  domainForm: FormGroup;
+
+  displayedColumns: string[] = ['username', 'fullName', 'roleType', 'memberOf'];
+
+  data: MemberRo[] = [];
+
+  selectedMember: MemberRo;
+
+  filter: any = {};
+
+  filterName: string;
+
+  resultsLength = 0;
+  isLoadingResults = false;
+  @ViewChild(MatPaginator) paginator: MatPaginator;
+
+  constructor(private domainService: AdminDomainService,
+              private membershipService: MembershipService,
+              private alertService: AlertMessageService,
+              private dialog: MatDialog,
+              private formBuilder: FormBuilder) {
+
+    this.domainForm = formBuilder.group({
+      'domainCode': new FormControl({value: '', readonly: true})
+    });
+
+  }
+
+  ngAfterViewInit() {
+    if (!!this._domain) {
+      this.loadTableData();
+    }
+  }
+
+  get domain(): DomainRo {
+    let newDomain = {...this._domain};
+
+    return newDomain;
+  }
+
+  @Input() set domain(value: DomainRo) {
+    this._domain = value;
+
+    if (!!value) {
+      this.loadTableData();
+    } else {
+      this.isLoadingResults = false;
+    }
+  }
+
+
+  onPageChanged(page: PageEvent) {
+    this.loadTableData();
+  }
+
+  loadTableData() {
+    if (!this._domain) {
+      return;
+    }
+
+    this.isLoadingResults = true;
+    this.membershipService.getDomainMembersObservable(this._domain.domainId, this.filter, this.paginator.pageIndex, this.paginator.pageSize)
+      .pipe(
+        finalize(() => {
+          this.isLoadingResults = false;
+        }))
+      .subscribe((result: TableResult<MemberRo>) => {
+          this.data = [...result.serviceEntities];
+          this.resultsLength = result.count;
+          this.isLoadingResults = false;
+        }
+      );
+  }
+
+  applyMemberFilter(event: Event) {
+    const filterValue = (event.target as HTMLInputElement).value;
+    this.filter["filter"] = filterValue.trim().toLowerCase();
+    this.refresh();
+  }
+
+  get submitButtonEnabled(): boolean {
+    return this.domainForm.valid && this.domainForm.dirty;
+  }
+
+  get inviteMemberDisabled(): boolean {
+    return !this._domain;
+  }
+
+  public memberSelected(member: MemberRo) {
+    this.selectedMember = member;
+  }
+
+  public onAddMemberButtonClicked() {
+    // add member
+    this.dialog.open(MemberDialogComponent, {
+      data: {
+        domain: this._domain,
+        member: this.createDomainMember(),
+        formTitle: "Invite new member to domain"
+      }
+    }).afterClosed().subscribe(value => {
+      this.refresh();
+    });
+  }
+
+  public refresh() {
+    if (this.paginator) {
+      this.paginator.firstPage();
+    }
+    this.loadTableData();
+  }
+
+  public createDomainMember(): MemberRo {
+    return {
+      memberOf: MemberTypeEnum.DOMAIN,
+      roleType: MembershipRoleEnum.VIEWER
+    } as MemberRo
+  }
+
+
+  public onEditSelectedButtonClicked() {
+    this.dialog.open(MemberDialogComponent, {
+      data: {
+        domain: this._domain,
+        member: this.selectedMember,
+        formTitle: "Edit member role for domain"
+      }
+    }).afterClosed().subscribe(value => {
+      this.refresh();
+    });
+  }
+  public onDeleteSelectedButtonClicked() {
+    this.membershipService.deleteMemberFromDomain(this._domain.domainId, this.selectedMember).subscribe(value => {
+      this.refresh();
+    });;
+  }
+
+  isDirty(): boolean {
+    return this.domainForm.dirty;
+  }
+
+  get domainNotSelected() {
+    return !this._domain
+  }
+}
+
+
+
+
+
+
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.css b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.css
new file mode 100644
index 000000000..1c224cec9
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.css
@@ -0,0 +1,13 @@
+.empty-field-label {
+  color: gray;
+}
+
+
+#custom-file-upload {
+  display: none;
+}
+
+.custom-file-upload {
+  display: inline-block;
+  cursor: pointer;
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.html b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.html
new file mode 100644
index 000000000..66c9c2922
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.html
@@ -0,0 +1,46 @@
+<h2 mat-dialog-title>{{formTitle}}</h2>
+<mat-dialog-content style="width:700px">
+  <form [formGroup]="memberForm">
+    <b *ngIf="newMode">You're inviting members to the SMP project.</b>
+    <mat-form-field  style="width: 100%">
+      <mat-label>Choose User to invite</mat-label>
+      <input id="member-user" type="text" matInput formControlName="member-user"
+             [matAutocomplete]="auto" (keyup)="applyUserFilter($event)"
+             required>
+      <mat-autocomplete #auto="matAutocomplete">
+        <mat-option *ngFor="let user of filteredOptions | async" [value]="user.username">
+          {{user.username}}
+        </mat-option>
+      </mat-autocomplete>
+      <mat-hint *ngIf="newMode">Type username or name to locate the user and select user from the list</mat-hint>
+    </mat-form-field>
+
+
+    <mat-form-field style="width:100%">
+      <mat-label>Select role for the user</mat-label>
+      <mat-select placeholder="Role for the member"
+                  formControlName="member-roleType"
+                  name="Role type"
+                  matTooltip="Role type for the member."
+                  id="member-user_id" required>
+        <mat-option *ngFor="let role of memberRoles"
+                    [value]="role.value">
+          {{role.key}}
+        </mat-option>
+      </mat-select>
+      <mat-hint> Chose member role</mat-hint>
+    </mat-form-field>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button mat-raised-button color="primary" (click)="closeDialog()">
+    <mat-icon>cancel</mat-icon>
+    <span>Close</span>
+  </button>
+  <button id="saveButton" mat-raised-button (click)="onSaveButtonClicked()" color="primary"
+          [disabled]="!submitButtonEnabled">
+    <mat-icon>save</mat-icon>
+    <span>Save</span>
+  </button>
+</mat-dialog-actions>
+
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.ts
new file mode 100644
index 000000000..ae0887867
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-dialog.component.ts
@@ -0,0 +1,138 @@
+import {Component, Inject, Input, OnInit} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
+import {FormBuilder, FormControl, FormGroup} from "@angular/forms";
+import {MembershipRoleEnum} from "../membership-role.enum";
+import {Observable} from "rxjs";
+import {SearchUserRo} from "./search-user-ro.model";
+import {MembershipService} from "../membership.service";
+import {MemberRo} from "../member-ro.model";
+import {DomainRo} from "../../domain-ro.model";
+import {MemberTypeEnum} from "./member-type.enum";
+import {AlertMessageService} from "../../../../common/alert-message/alert-message.service";
+
+
+@Component({
+  templateUrl: './member-dialog.component.html',
+  styleUrls: ['./member-dialog.component.css']
+})
+export class MemberDialogComponent implements OnInit {
+
+  formTitle = "Member dialog";
+  memberForm: FormGroup;
+
+  message: string;
+  messageType: string = "alert-error";
+
+  currentFilter: string;
+
+  _currentMember: MemberRo;
+  _currentDomain: DomainRo;
+
+  filteredOptions: Observable<SearchUserRo[]>;
+
+  readonly memberRoles = Object.keys(MembershipRoleEnum).map(el => {
+    return {key: el, value: MembershipRoleEnum[el]}
+  });
+
+
+  constructor(@Inject(MAT_DIALOG_DATA) public data: any,
+              private membershipService: MembershipService,
+              public dialogRef: MatDialogRef<MemberDialogComponent>,
+              private alertService: AlertMessageService,
+              private formBuilder: FormBuilder
+  ) {
+    dialogRef.disableClose = true;//disable default close operation
+    this.formTitle = data.formTitle;
+    this._currentDomain = data.domain;
+
+    this.memberForm = formBuilder.group({
+      'member-user': new FormControl({value: null}),
+      'member-fullName': new FormControl({value: null}),
+      'member-memberOf': new FormControl({value: null}),
+      'member-roleType': new FormControl({value: null})
+    });
+    this.member = {
+      ...data.member
+    };
+    this.currentFilter = "";
+  }
+
+  get member(): MemberRo {
+    let member = {...this._currentMember};
+    member.username = this.memberForm.get('member-user').value;
+    member.fullName = this.memberForm.get('member-fullName').value;
+    member.memberOf = this.memberForm.get('member-memberOf').value;
+    member.roleType = this.memberForm.get('member-roleType').value;
+    return member;
+  }
+
+  get newMode(): boolean {
+    return !this._currentMember?.memberId;
+  }
+
+  @Input() set member(value: MemberRo) {
+    this._currentMember = value;
+
+    if (!!value) {
+      this.memberForm.controls['member-user'].setValue(value.username);
+      // control disable enable did not work??
+      if (this.newMode) {
+        this.memberForm.controls['member-user'].enable();
+      } else {
+        this.memberForm.controls['member-user'].disable();
+      }
+
+      this.memberForm.controls['member-fullName'].setValue(value.fullName);
+      this.memberForm.controls['member-memberOf'].setValue(value.memberOf);
+      this.memberForm.controls['member-roleType'].setValue(value.roleType);
+
+    } else {
+      this.memberForm.controls['member-user'].setValue("");
+      this.memberForm.controls['member-fullName'].setValue("");
+      this.memberForm.controls['member-memberOf'].setValue("");
+      this.memberForm.controls['member-roleType'].setValue("");
+    }
+
+  }
+
+  ngOnInit() {
+    this.filteredOptions = this.membershipService.getUserLookupObservable("");
+  }
+
+  applyUserFilter(event: Event) {
+    let filterValue = (event.target as HTMLInputElement).value;
+    if (this.currentFilter == filterValue) {
+      // ignore update
+      return;
+    }
+    this.currentFilter = filterValue
+    this.filteredOptions = this.membershipService.getUserLookupObservable(filterValue.trim().toLowerCase());
+  }
+
+  clearAlert() {
+    this.message = null;
+    this.messageType = null;
+  }
+
+
+  closeDialog() {
+    this.dialogRef.close()
+  }
+
+  get submitButtonEnabled(): boolean {
+    return this.memberForm.valid && this.memberForm.dirty;
+  }
+
+  public onSaveButtonClicked() {
+    let member = this.member;
+    if (member.memberOf == MemberTypeEnum.DOMAIN) {
+      this.membershipService.addEditMemberToDomain(this._currentDomain.domainId, this.member).subscribe((member: MemberRo) => {
+        if (!!member) {
+          this.closeDialog();
+        }
+      }, (error)=> {
+        this.alertService.error(error.error?.errorDescription)
+      });
+    }
+  }
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-type.enum.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-type.enum.ts
new file mode 100644
index 000000000..734fb7c97
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-type.enum.ts
@@ -0,0 +1,8 @@
+export enum MemberTypeEnum {
+  /**
+   * Resource, group of domain is marked as PUBLIC.
+   */
+  DOMAIN= 'DOMAIN',
+  GROUP= 'GROUP',
+  RESOURCE= 'RESOURCE',
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/search-user-ro.model.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/search-user-ro.model.ts
new file mode 100644
index 000000000..84ff26cd3
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/search-user-ro.model.ts
@@ -0,0 +1,9 @@
+import {SearchTableEntity} from "../../../../common/search-table/search-table-entity.model";
+
+export interface SearchUserRo extends SearchTableEntity {
+  userId: string,
+  username: string;
+  fullName: string;
+
+}
+
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-ro.model.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-ro.model.ts
new file mode 100644
index 000000000..d42464599
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-ro.model.ts
@@ -0,0 +1,13 @@
+
+import {MembershipRoleEnum} from "./membership-role.enum";
+import {SearchTableEntity} from "../../../common/search-table/search-table-entity.model";
+import {MemberTypeEnum} from "./member-dialog/member-type.enum";
+
+export interface MemberRo extends SearchTableEntity {
+
+  memberId:string;
+  username:string;
+  memberOf:MemberTypeEnum;
+  fullName:string;
+  roleType:MembershipRoleEnum;
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts
new file mode 100644
index 000000000..8f8bf7c64
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts
@@ -0,0 +1,7 @@
+export enum MembershipRoleEnum {
+  /**
+   * Resource, group of domain is marked as PUBLIC.
+   */
+  VIEWER= 'VIEWER',
+  ADMIN= 'ADMIN'
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership.service.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership.service.ts
new file mode 100644
index 000000000..364f024dc
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership.service.ts
@@ -0,0 +1,71 @@
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs';
+import {SearchTableResult} from "../../../common/search-table/search-table-result.model";
+import {User} from "../../../security/user.model";
+import {HttpClient, HttpParams} from "@angular/common/http";
+import {SmpConstants} from "../../../smp.constants";
+import {SecurityService} from "../../../security/security.service";
+import {AlertMessageService} from "../../../common/alert-message/alert-message.service";
+import {MemberRo} from "./member-ro.model";
+import {TableResult} from "./table-result.model";
+import {SearchUserRo} from "./member-dialog/search-user-ro.model";
+import {MembershipRoleEnum} from "./membership-role.enum";
+
+
+@Injectable()
+export class MembershipService {
+
+
+  constructor(
+    private http: HttpClient,
+    private securityService: SecurityService,
+    private alertService: AlertMessageService) {
+  }
+
+
+  getDomainMembersObservable(domainID: string, filter: any, page: number, pageSize: number): Observable<SearchTableResult> {
+    const currentUser: User = this.securityService.getCurrentUser();
+
+    let params: HttpParams = new HttpParams()
+      .set('page', page.toString())
+      .set('pageSize', pageSize.toString());
+
+    for (let filterProperty in filter) {
+      if (filter.hasOwnProperty(filterProperty)) {
+        // must encode else problem with + sign
+        params = params.set(filterProperty, encodeURIComponent(filter[filterProperty]));
+      }
+    }
+
+    return this.http.get<TableResult<MemberRo>>(SmpConstants.REST_PUBLIC_DOMAIN_MEMBERS
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domainID), {params});
+  }
+
+  getUserLookupObservable(filter: string): Observable<SearchUserRo[]> {
+    const currentUser: User = this.securityService.getCurrentUser();
+    let params: HttpParams = new HttpParams()
+      .set('filter', filter);
+    return this.http.get<SearchUserRo[]>(SmpConstants.REST_PUBLIC_USER_SEARCH
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId), {params});
+  }
+
+
+  addEditMemberToDomain(domainId: string, member: MemberRo): Observable<MemberRo> {
+    const currentUser: User = this.securityService.getCurrentUser();
+
+    return this.http.put<MemberRo>(SmpConstants.REST_PUBLIC_DOMAIN_MEMBERS_ADD
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domainId),member);
+  }
+
+  deleteMemberFromDomain( domainId: string, member: MemberRo): Observable<MemberRo> {
+    const currentUser: User = this.securityService.getCurrentUser();
+
+    return this.http.delete<MemberRo>(SmpConstants.REST_PUBLIC_DOMAIN_MEMBERS_DELETE
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domainId)
+      .replace(SmpConstants.PATH_PARAM_ENC_MEMBER_ID, member.memberId));
+  }
+
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/table-result.model.ts b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/table-result.model.ts
new file mode 100644
index 000000000..ae03b2514
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/table-result.model.ts
@@ -0,0 +1,8 @@
+
+
+export interface TableResult<T> {
+  serviceEntities: T[];
+  pageSize: number;
+  count: number;
+  filter: any;
+}
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts
index 312422f3d..eaac8abf2 100644
--- a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts
+++ b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts
@@ -8,6 +8,7 @@ import {CertificateRo} from "../../user/certificate-ro.model";
 import {VisibilityEnum} from "../../../common/enums/visibility.enum";
 import {ResourceDefinitionRo} from "../../admin-extension/resource-definition-ro.model";
 import {BeforeLeaveGuard} from "../../../window/sidenav/navigation-on-leave-guard";
+import {UserRo} from "../../user/user-ro.model";
 
 
 @Component({
diff --git a/smp-angular/src/app/system-settings/user/user-ro.model.ts b/smp-angular/src/app/system-settings/user/user-ro.model.ts
index 03a6a62ec..fbcfe70c9 100644
--- a/smp-angular/src/app/system-settings/user/user-ro.model.ts
+++ b/smp-angular/src/app/system-settings/user/user-ro.model.ts
@@ -4,6 +4,7 @@ import {CertificateRo} from './certificate-ro.model';
 export interface UserRo extends SearchTableEntity {
   userId?: string
   username: string;
+  fullName?: string;
   emailAddress: string;
   accessTokenId?: string;
   passwordExpireOn?:	Date;
diff --git a/smp-angular/src/app/user-settings/user-profile/user-profile.component.html b/smp-angular/src/app/user-settings/user-profile/user-profile.component.html
index 1272873cd..7b00ffa2d 100644
--- a/smp-angular/src/app/user-settings/user-profile/user-profile.component.html
+++ b/smp-angular/src/app/user-settings/user-profile/user-profile.component.html
@@ -1,5 +1,5 @@
 <div id="user-profile-panel">
-  <form [formGroup]="userForm" (ngSubmit)="onSaveButtonClicked()">
+  <form [formGroup]="userForm" >
     <data-panel title="Account"
                 text="Account data">
       <mat-form-field class="user-profile-pane-field">
@@ -102,7 +102,7 @@
       </div>
     </data-panel>
   </form>
-  <form [formGroup]="userCredentialForm" (ngSubmit)="onSaveButtonClicked()">
+  <form [formGroup]="userCredentialForm">
     <data-panel *ngIf="true" title="Username/password credentials"
                 text="Reset username password for the UI login">
       <div style="display: flex;flex-flow: row wrap;">
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainMemberToMemberROConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainMemberToMemberROConverter.java
new file mode 100644
index 000000000..8f1918328
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainMemberToMemberROConverter.java
@@ -0,0 +1,27 @@
+package eu.europa.ec.edelivery.smp.conversion;
+
+import eu.europa.ec.edelivery.smp.data.model.user.DBDomainMember;
+import eu.europa.ec.edelivery.smp.data.ui.MemberRO;
+import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class DBDomainMemberToMemberROConverter implements Converter<DBDomainMember, MemberRO> {
+
+    @Override
+    public MemberRO convert(DBDomainMember source) {
+        MemberRO target = new MemberRO();
+        target.setMemberOf("DOMAIN");
+        target.setUsername(source.getUser().getUsername());
+        target.setFullName(source.getUser().getFullName());
+        target.setRoleType(source.getRole());
+        target.setMemberId(SessionSecurityUtils.encryptedEntityId(source.getId()));
+
+        return target;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToSearchUserROConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToSearchUserROConverter.java
new file mode 100644
index 000000000..83dfba2c4
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBUserToSearchUserROConverter.java
@@ -0,0 +1,24 @@
+package eu.europa.ec.edelivery.smp.conversion;
+
+import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
+import eu.europa.ec.edelivery.smp.data.ui.SearchUserRO;
+import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class DBUserToSearchUserROConverter implements Converter<DBUser, SearchUserRO> {
+
+    @Override
+    public SearchUserRO convert(DBUser source) {
+        SearchUserRO target = new SearchUserRO();
+        target.setUsername(source.getUsername());
+        target.setFullName(source.getFullName());
+        target.setUserId(SessionSecurityUtils.encryptedEntityId(source.getId()));
+        return target;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDao.java
index a9bc27da8..f04fc0c7d 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDao.java
@@ -16,10 +16,8 @@ package eu.europa.ec.edelivery.smp.data.dao;
 import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
 import eu.europa.ec.edelivery.smp.data.model.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.user.DBDomainMember;
-import eu.europa.ec.edelivery.smp.data.model.user.DBGroupMember;
 import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
-import eu.europa.ec.edelivery.smp.logging.SMPLogger;
-import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Repository;
 
 import javax.persistence.TypedQuery;
@@ -37,15 +35,16 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
 public class DomainMemberDao extends BaseDao<DBDomainMember> {
 
 
-    public boolean isUserDomainMember(DBUser user, DBDomain domain){
+    public boolean isUserDomainMember(DBUser user, DBDomain domain) {
         return isUserDomainsMember(user.getId(), Collections.singletonList(domain.getId()));
     }
-    public boolean  isUserDomainsMember(DBUser user, List<DBDomain> domainList){
+
+    public boolean isUserDomainsMember(DBUser user, List<DBDomain> domainList) {
         List<Long> domainIds = domainList.stream().map(dbDomain -> dbDomain.getId()).collect(Collectors.toList());
         return isUserDomainsMember(user.getId(), domainIds);
     }
 
-    public boolean  isUserDomainsMember(Long userId, List<Long> domainIdList){
+    public boolean isUserDomainsMember(Long userId, List<Long> domainIdList) {
         TypedQuery<Long> query = memEManager.createNamedQuery(QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS_COUNT,
                 Long.class);
         query.setParameter(PARAM_USER_ID, userId);
@@ -58,7 +57,45 @@ public class DomainMemberDao extends BaseDao<DBDomainMember> {
 
         query.setParameter(PARAM_USER_ID, userId);
         query.setParameter(PARAM_DOMAIN_IDS, domainsIds);
-        return query.getResultList().stream().anyMatch(member ->member.getRole() == roleType );
+        return query.getResultList().stream().anyMatch(member -> member.getRole() == roleType);
+    }
+
+    public List<DBDomainMember> getDomainMembers(Long domainId, int iPage, int iPageSize, String filter) {
+        boolean hasFilter = StringUtils.isNotBlank(filter);
+        TypedQuery<DBDomainMember> query = memEManager.createNamedQuery(hasFilter ?
+                QUERY_DOMAIN_MEMBERS_FILTER : QUERY_DOMAIN_MEMBERS, DBDomainMember.class);
+
+        if (iPageSize> -1 && iPage >-1 ) {
+            query.setFirstResult(iPage * iPageSize);
+        }
+        if (iPageSize> 0) {
+            query.setMaxResults(iPageSize);
+        }
+        query.setParameter(PARAM_DOMAIN_ID, domainId);
+        if (hasFilter) {
+            query.setParameter(PARAM_USER_FILTER, "%"+StringUtils.trim(filter)+"%");
+        }
+        return query.getResultList();
+    }
+
+    public Long getDomainMemberCount(Long domainId, String filter) {
+        boolean hasFilter = StringUtils.isNotBlank(filter);
+        TypedQuery<Long> query = memEManager.createNamedQuery(hasFilter ? QUERY_DOMAIN_MEMBERS_FILTER_COUNT : QUERY_DOMAIN_MEMBERS_COUNT, Long.class);
+        query.setParameter(PARAM_DOMAIN_ID, domainId);
+        if (hasFilter) {
+            query.setParameter(PARAM_USER_FILTER, "%"+StringUtils.trim(filter)+"%");
+        }
+        return query.getSingleResult();
+    }
+
+
+    public DBDomainMember addMemberToDomain(DBDomain domain, DBUser user , MembershipRoleType role){
+        DBDomainMember domainMember = new DBDomainMember();
+        domainMember.setRole(role);
+        domainMember.setUser(user);
+        domainMember.setDomain(domain);
+        domainMember = merge(domainMember);
+        return domainMember;
     }
 
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
index 91adae188..aa93f3db7 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
@@ -25,7 +25,11 @@ public class QueryNames {
     public static final String QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS_COUNT = "DBDomainMember.getByUserAndDomainsCount";
     public static final String QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS = "DBDomainMember.getByUserAndDomains";
 
+    public static final String QUERY_DOMAIN_MEMBERS_COUNT = "DBDomainMember.getByDomainCount";
 
+    public static final String QUERY_DOMAIN_MEMBERS_FILTER_COUNT = "DBDomainMember.getByDomainFilterCount";
+    public static final String QUERY_DOMAIN_MEMBERS = "DBDomainMember.getByDomain";
+    public static final String QUERY_DOMAIN_MEMBERS_FILTER = "DBDomainMember.getByDomainFilter";
 
     public static final String QUERY_DOMAIN_RESOURCE_DEF_ALL = "DBDomainResourceDef.getAll";
     public static final String QUERY_DOMAIN_RESOURCE_DEF_DOMAIN_ALL = "DBDomainResourceDef.getAllForDomain";
@@ -79,6 +83,10 @@ public class QueryNames {
     public static final String QUERY_USER_BY_CREDENTIAL_NAME_TYPE_TARGET = "DBUser.getUserByCredentialNameTypeTarget";
     public static final String QUERY_USER_BY_CI_CREDENTIAL_NAME_TYPE_TARGET = "DBUser.getUserByCaseInsensitiveCredentialNameTypeTarget";
 
+    public static final String QUERY_USER_COUNT = "DBUser.getUsersCount";
+    public static final String QUERY_USER_FILTER_COUNT = "DBUser.getUsersByFilterCount";
+    public static final String QUERY_USERS = "DBUser.getUsers";
+    public static final String QUERY_QUERY_USERS_FILTER = "DBUser.getUsersByFilter";
 
 
     public static final String PARAM_NAME = "name";
@@ -86,6 +94,9 @@ public class QueryNames {
     public static final String PARAM_IDENTIFIER = "identifier";
     public static final String PARAM_ID = "id";
 
+    public static final String PARAM_USER_FILTER = "user_filter";
+
+
 
     public static final String PARAM_URL_SEGMENT = "url_segment";
     public static final String PARAM_EXTENSION_ID = "extension_id";
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java
index 8d354e31e..f3f0d68fb 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java
@@ -316,4 +316,31 @@ public class UserDao extends BaseDao<DBUser> {
         }
         */
     }
+
+    public List<DBUser> getFilteredUserList(int iPage, int iPageSize, String filter) {
+        boolean hasFilter = StringUtils.isNotBlank(filter);
+        TypedQuery<DBUser> query = memEManager.createNamedQuery(hasFilter ?
+                QUERY_QUERY_USERS_FILTER : QUERY_USERS, DBUser.class);
+
+        if (iPageSize > -1 && iPage > -1) {
+            query.setFirstResult(iPage * iPageSize);
+        }
+        if (iPageSize > 0) {
+            query.setMaxResults(iPageSize);
+        }
+
+        if (hasFilter) {
+            query.setParameter(PARAM_USER_FILTER, "%" + StringUtils.trim(filter) + "%");
+        }
+        return query.getResultList();
+    }
+
+    public Long getFilteredUserListCount(String filter) {
+        boolean hasFilter = StringUtils.isNotBlank(filter);
+        TypedQuery<Long> query = memEManager.createNamedQuery(hasFilter ? QUERY_USER_FILTER_COUNT : QUERY_USER_COUNT, Long.class);
+        if (hasFilter) {
+            query.setParameter(PARAM_USER_FILTER, "%" + StringUtils.trim(filter) + "%");
+        }
+        return query.getSingleResult();
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBDomainMember.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBDomainMember.java
index f3c844085..9967e2572 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBDomainMember.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBDomainMember.java
@@ -4,6 +4,8 @@ import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
 import eu.europa.ec.edelivery.smp.data.model.BaseEntity;
 import eu.europa.ec.edelivery.smp.data.model.CommonColumnsLengths;
 import eu.europa.ec.edelivery.smp.data.model.DBDomain;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.hibernate.annotations.GenericGenerator;
 import org.hibernate.envers.Audited;
 
@@ -22,13 +24,19 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
 @Table(name = "SMP_DOMAIN_MEMBER",
         indexes = {@Index(name = "SMP_DOM_MEM_IDX", columnList = "FK_DOMAIN_ID, FK_USER_ID", unique = true)
 })
-@NamedQueries({
-        @NamedQuery(name = QUERY_DOMAIN_MEMBER_ALL, query = "SELECT u FROM DBDomainMember u"),
-        @NamedQuery(name = QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS_COUNT, query = "SELECT count(c) FROM DBDomainMember c " +
-                "WHERE c.user.id = :user_id and c.domain.id in (:domain_ids)"),
-        @NamedQuery(name = QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS, query = "SELECT c FROM DBDomainMember c " +
-                "WHERE c.user.id = :user_id and c.domain.id in (:domain_ids)")
-})
+@NamedQuery(name = QUERY_DOMAIN_MEMBER_ALL, query = "SELECT u FROM DBDomainMember u")
+@NamedQuery(name = QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS_COUNT, query = "SELECT count(c) FROM DBDomainMember c " +
+        "WHERE c.user.id = :user_id and c.domain.id in (:domain_ids)")
+@NamedQuery(name = QUERY_DOMAIN_MEMBER_BY_USER_DOMAINS, query = "SELECT c FROM DBDomainMember c " +
+        "WHERE c.user.id = :user_id and c.domain.id in (:domain_ids)")
+@NamedQuery(name = QUERY_DOMAIN_MEMBERS_COUNT, query = "SELECT count(c) FROM DBDomainMember c " +
+        " WHERE c.domain.id = :domain_id")
+@NamedQuery(name = QUERY_DOMAIN_MEMBERS, query = "SELECT c FROM DBDomainMember c " +
+        " WHERE c.domain.id = :domain_id order by c.user.username")
+@NamedQuery(name = QUERY_DOMAIN_MEMBERS_FILTER_COUNT, query = "SELECT count(c) FROM DBDomainMember c " +
+        " WHERE c.domain.id = :domain_id AND (lower(c.user.fullName) like lower(:user_filter) OR  lower(c.user.username) like lower(:user_filter))")
+@NamedQuery(name = QUERY_DOMAIN_MEMBERS_FILTER, query = "SELECT c FROM DBDomainMember c " +
+        " WHERE c.domain.id = :domain_id  AND (lower(c.user.fullName) like lower(:user_filter) OR  lower(c.user.username) like lower(:user_filter))  order by c.user.username")
 public class DBDomainMember extends BaseEntity {
 
     @Id
@@ -93,4 +101,20 @@ public class DBDomainMember extends BaseEntity {
     public void setRole(MembershipRoleType role) {
         this.role = role;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DBDomainMember that = (DBDomainMember) o;
+
+        return new EqualsBuilder().appendSuper(super.equals(o)).append(id, that.id).append(domain, that.domain).append(user, that.user).append(role, that.role).isEquals();
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 37).appendSuper(super.hashCode()).append(id).append(role).toHashCode();
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBUser.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBUser.java
index 72598a68c..f9fa64425 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBUser.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/user/DBUser.java
@@ -25,6 +25,8 @@ import org.hibernate.envers.Audited;
 import javax.persistence.*;
 import java.util.Objects;
 
+import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
+
 @Entity
 @Audited
 @Table(name = "SMP_USER")
@@ -38,6 +40,16 @@ import java.util.Objects;
         " WHERE upper(c.name) = upper(:credential_name) " +
         " AND c.credentialType = :credential_type " +
         " AND c.credentialTarget = :credential_target")
+
+
+@NamedQuery(name = QUERY_USER_COUNT, query = "SELECT count(c) FROM DBUser c")
+@NamedQuery(name = QUERY_USERS, query = "SELECT c FROM DBUser c  order by c.username")
+@NamedQuery(name = QUERY_USER_FILTER_COUNT, query = "SELECT count(c) FROM DBUser c " +
+        " WHERE (lower(c.username) like lower(:user_filter) OR  lower(c.fullName) like lower(:user_filter))")
+@NamedQuery(name = QUERY_QUERY_USERS_FILTER, query = "SELECT c FROM DBUser c " +
+        " WHERE (lower(c.username) like lower(:user_filter) OR  lower(c.fullName) like lower(:user_filter))  order by c.username")
+
+
 //@NamedQueries({
 
 // @NamedQuery(name = "DBUser.getUserByCertificateId", query = "SELECT u FROM DBUser u WHERE u.certificate.certificateId = :certificateId"),
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/MemberRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/MemberRO.java
new file mode 100644
index 000000000..b90802239
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/MemberRO.java
@@ -0,0 +1,52 @@
+package eu.europa.ec.edelivery.smp.data.ui;
+
+import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
+
+public class MemberRO {
+
+    String memberId;
+    String username;
+    String memberOf;
+    String fullName;
+    MembershipRoleType roleType;
+
+    public String getMemberId() {
+        return memberId;
+    }
+
+    public void setMemberId(String memberId) {
+        this.memberId = memberId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getMemberOf() {
+        return memberOf;
+    }
+
+    public void setMemberOf(String memberOf) {
+        this.memberOf = memberOf;
+    }
+
+    public String getFullName() {
+        return fullName;
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+
+    public MembershipRoleType getRoleType() {
+        return roleType;
+    }
+
+    public void setRoleType(MembershipRoleType roleType) {
+        this.roleType = roleType;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SearchUserRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SearchUserRO.java
new file mode 100644
index 000000000..2051d4d8a
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/SearchUserRO.java
@@ -0,0 +1,32 @@
+package eu.europa.ec.edelivery.smp.data.ui;
+
+public class SearchUserRO {
+
+    String userId;
+    String username;
+    String fullName;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getFullName() {
+        return fullName;
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainPublicService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainPublicService.java
index 7fe169ab2..416f47474 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainPublicService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainPublicService.java
@@ -2,13 +2,25 @@ package eu.europa.ec.edelivery.smp.services.ui;
 
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.DomainDao;
+import eu.europa.ec.edelivery.smp.data.dao.DomainMemberDao;
+import eu.europa.ec.edelivery.smp.data.dao.UserDao;
 import eu.europa.ec.edelivery.smp.data.model.DBDomain;
+import eu.europa.ec.edelivery.smp.data.model.user.DBDomainMember;
+import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
 import eu.europa.ec.edelivery.smp.data.ui.DomainPublicRO;
+import eu.europa.ec.edelivery.smp.data.ui.MemberRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.ConversionService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * Service bean provides only public domain entity data for the Domain.
@@ -20,8 +32,19 @@ import org.springframework.stereotype.Service;
 public class UIDomainPublicService extends UIServiceBase<DBDomain, DomainPublicRO> {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIDomainPublicService.class);
-    @Autowired
-    DomainDao domainDao;
+    private final DomainDao domainDao;
+
+    private final DomainMemberDao domainMemberDao;
+    private final UserDao userDao;
+    private final ConversionService conversionService;
+
+
+    public UIDomainPublicService(DomainDao domainDao, DomainMemberDao domainMemberDao,ConversionService conversionService, UserDao userDao) {
+        this.domainDao = domainDao;
+        this.domainMemberDao = domainMemberDao;
+        this.conversionService = conversionService;
+        this.userDao = userDao;
+    }
 
     @Override
     protected BaseDao<DBDomain> getDatabaseDao() {
@@ -44,4 +67,59 @@ public class UIDomainPublicService extends UIServiceBase<DBDomain, DomainPublicR
         LOG.debug("Query for public domain data: page: [{}], page size [{}], sort: [{}], filter: [{}].", page, pageSize, sortField, filter);
         return super.getTableList(page, pageSize, sortField, sortOrder, filter);
     }
+
+
+    @Transactional
+    public ServiceResult<MemberRO> getDomainMembers(Long domainId, int page, int pageSize,
+                                                   String filter) {
+        Long count = domainMemberDao.getDomainMemberCount(domainId, filter);
+        ServiceResult<MemberRO> result =  new ServiceResult<>();
+        result.setPage(page);
+        result.setPageSize(pageSize);
+        if (count<1) {
+            result.setCount(0L);
+            return result;
+        }
+        result.setCount(count);
+        List<DBDomainMember> memberROS = domainMemberDao.getDomainMembers(domainId, page, pageSize, filter);
+        List<MemberRO> memberList = memberROS.stream().map(member-> conversionService.convert(member, MemberRO.class)).collect(Collectors.toList());
+
+        result.getServiceEntities().addAll(memberList);
+        return result;
+    }
+
+    @Transactional
+    public MemberRO addMemberToDomain(Long domainId, MemberRO memberRO, Long memberId) {
+        LOG.info("Add member [{}] to domain [{}]", memberRO.getUsername(), domainId);
+        DBUser user = userDao.findUserByUsername(memberRO.getUsername())
+                .orElseThrow(() -> new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "Add/edit membership", "User ["+memberRO.getUsername()+"] does not exists!"));
+
+        DBDomainMember domainMember;
+        if (memberId !=null) {
+            domainMember = domainMemberDao.find(memberId);
+            domainMember.setRole(memberRO.getRoleType());
+        } else {
+            DBDomain domain = domainDao.find(domainId);
+            if (domainMemberDao.isUserDomainMember(user, domain)) {
+                throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "Add membership", "User ["+memberRO.getUsername()+"] is already a member!");
+            }
+            domainMember = domainMemberDao.addMemberToDomain(domain, user,memberRO.getRoleType() );
+        }
+        return conversionService.convert(domainMember, MemberRO.class);
+    }
+
+    @Transactional
+    public MemberRO deleteMemberFromDomain(Long domainId, Long memberId) {
+        LOG.info("Delete member [{}] from domain [{}]", memberId, domainId);
+        DBDomainMember domainMember = domainMemberDao.find(memberId);
+        if (domainMember == null) {
+            throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "Membership", "Membership does not exists!");
+        }
+        if (!Objects.equals(domainMember.getDomain().getId(),domainId  )){
+            throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "Membership", "Membership does not belong to domain!");
+        }
+
+        domainMemberDao.remove(domainMember);
+        return conversionService.convert(domainMember, MemberRO.class);
+    }
 }
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 074c9c6eb..f5861488c 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
@@ -204,7 +204,6 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         return result;
     }
 
-
     /**
      * Method updates the user password
      *
@@ -270,6 +269,7 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         return dbCredential.getUser();
     }
 
+
     /**
      * Method creates Username/passwords credentials for the user with given userId.
      * The method must be called inside active transactions.
@@ -493,6 +493,26 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         return credentialResultRO;
     }
 
+    @Transactional
+    public ServiceResult<SearchUserRO> searchUsers(int page, int pageSize, String filter) {
+        Long count = userDao.getFilteredUserListCount(filter);
+        ServiceResult<SearchUserRO> result = new ServiceResult<>();
+        result.setPage(page);
+        result.setPageSize(pageSize);
+        ;
+        if (count < 1) {
+            result.setCount(0L);
+            return result;
+        }
+        result.setCount(count);
+        List<DBUser> users = userDao.getFilteredUserList(page, pageSize, filter);
+        List<SearchUserRO> userList = users.stream().map(usr -> conversionService.convert(usr, SearchUserRO.class)).collect(Collectors.toList());
+
+        result.getServiceEntities().addAll(userList);
+        return result;
+    }
+
+
     @Transactional(readOnly = true)
     public DBUser findUserByUsername(String userName) {
         return userDao.findUserByUsername(userName).orElseThrow(() -> new SMPRuntimeException(ErrorCode.USER_NOT_EXISTS));
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDaoTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDaoTest.java
index be940cffe..b5373da1c 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDaoTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainMemberDaoTest.java
@@ -4,15 +4,15 @@ import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
 import eu.europa.ec.edelivery.smp.data.model.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.user.DBDomainMember;
 import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
-import eu.europa.ec.edelivery.smp.testutil.TestConstants;
-import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.Collections;
+import java.util.List;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  * @author Joze Rihtarsic
@@ -27,16 +27,19 @@ public class DomainMemberDaoTest extends AbstractBaseDao {
     @Autowired
     DomainMemberDao testInstance;
 
+    @Before
+    public void prepareDatabase() {
+        testUtilsDao.clearData();
+        testUtilsDao.createUsers();
+        testUtilsDao.createDomains();
+    }
+
+
     @Test
     public void testIsUserDomainsMember() {
-        DBUser user = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1);
-        DBDomain domain = TestDBUtils.createDBDomain();
-        userDao.persistFlushDetach(user);
-        domainDao.persistFlushDetach(domain);
-        DBDomainMember domainMember = new DBDomainMember();
-        domainMember.setDomain(domain);
-        domainMember.setUser(user);
-        testInstance.persistFlushDetach(domainMember);
+        DBDomain domain = testUtilsDao.getD1();
+        DBUser user = testUtilsDao.getUser1();
+        addMemberToDomain(user, domain, MembershipRoleType.ADMIN);
         // then
         boolean result = testInstance.isUserDomainsMember(user, Collections.singletonList(domain));
 
@@ -45,31 +48,77 @@ public class DomainMemberDaoTest extends AbstractBaseDao {
 
     @Test
     public void testIsUserDomainsMemberFalse() {
-        DBUser user = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1);
-        DBDomain domain = TestDBUtils.createDBDomain();
-        userDao.persistFlushDetach(user);
-        domainDao.persistFlushDetach(domain);
+
         // then
-        boolean result = testInstance.isUserDomainsMember(user, Collections.singletonList(domain));
+        boolean result = testInstance.isUserDomainsMember(testUtilsDao.getUser1(), Collections.singletonList(testUtilsDao.getD1()));
 
         assertFalse(result);
     }
 
     @Test
     public void testIsUserDomainsMemberWithRoleTrue() {
-        DBUser user = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1);
-        DBDomain domain = TestDBUtils.createDBDomain();
-        userDao.persistFlushDetach(user);
-        domainDao.persistFlushDetach(domain);
-        DBDomainMember domainMember = new DBDomainMember();
-        domainMember.setDomain(domain);
-        domainMember.setUser(user);
-        domainMember.setRole(MembershipRoleType.ADMIN);
-        testInstance.persistFlushDetach(domainMember);
+        DBDomain domain = testUtilsDao.getD1();
+        DBUser user = testUtilsDao.getUser1();
+        addMemberToDomain(user, domain, MembershipRoleType.ADMIN);
         // then
         boolean result = testInstance.isUserDomainMemberWithRole(user.getId(), Collections.singletonList(domain.getId()), MembershipRoleType.ADMIN);
         assertTrue(result);
         result = testInstance.isUserDomainMemberWithRole(user.getId(), Collections.singletonList(domain.getId()), MembershipRoleType.VIEWER);
         assertFalse(result);
     }
+
+    @Test
+    public void testGetDomainMembersEmpty() {
+        DBDomain domain = testUtilsDao.getD1();
+        // then
+        Long resultCount = testInstance.getDomainMemberCount(domain.getId(), null);
+        List<DBDomainMember> result = testInstance.getDomainMembers(domain.getId(), 0, 10, null);
+        assertEquals(0, resultCount.intValue());
+        assertEquals(0, result.size());
+    }
+
+    @Test
+    public void testGetDomainMembersOne() {
+        DBDomain domain = testUtilsDao.getD1();
+        DBUser user = testUtilsDao.getUser1();
+        addMemberToDomain(user, domain, MembershipRoleType.ADMIN);
+        // then
+        Long resultCount = testInstance.getDomainMemberCount(domain.getId(), null);
+        List<DBDomainMember> result = testInstance.getDomainMembers(domain.getId(), 0, 10, null);
+        assertEquals(1, resultCount.intValue());
+        assertEquals(1, result.size());
+    }
+
+    @Test
+    public void testGetDomainMembersOneFilter() {
+        DBDomain domain = testUtilsDao.getD1();
+        DBUser user = testUtilsDao.getUser1();
+        addMemberToDomain(user, domain, MembershipRoleType.ADMIN);
+        // then filter no match
+        assertFilter("NotExistsAtAll", 0, domain);
+        assertFilter(user.getUsername(), 1, domain);
+        assertFilter(user.getFullName(), 1, domain);
+
+        assertFilter(StringUtils.upperCase(user.getUsername()), 1, domain);
+        assertFilter(StringUtils.upperCase(user.getFullName()), 1, domain);
+        assertFilter(StringUtils.lowerCase(user.getUsername()), 1, domain);
+        assertFilter(StringUtils.lowerCase(user.getFullName()), 1, domain);
+        assertFilter("", 1, domain);
+        assertFilter(null, 1, domain);
+    }
+
+    private void assertFilter(String filter, int expectedCount, DBDomain domain) {
+        Long resultCount = testInstance.getDomainMemberCount(domain.getId(), filter);
+        List<DBDomainMember> result = testInstance.getDomainMembers(domain.getId(), 0, 10, filter);
+        assertEquals(expectedCount, resultCount.intValue());
+        assertEquals(expectedCount, result.size());
+    }
+
+    private void addMemberToDomain(DBUser user, DBDomain domain, MembershipRoleType role) {
+        DBDomainMember domainMember = new DBDomainMember();
+        domainMember.setDomain(domain);
+        domainMember.setUser(user);
+        domainMember.setRole(role);
+        testInstance.persistFlushDetach(domainMember);
+    }
 }
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 5d65fe1a5..0a8f42fbd 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
@@ -22,11 +22,8 @@ import org.springframework.test.context.ContextConfiguration;
 public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest {
     @Rule
     public ExpectedException expectedExeption = ExpectedException.none();
-
     @Autowired
     protected UIUserService testInstance;
-
-
     @Autowired
     protected ResourceDao serviceGroupDao;
 /*
diff --git a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
index 7f56ba1ad..0490d286a 100644
--- a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
+++ b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
@@ -109,3 +109,7 @@ insert into SMP_GROUP_MEMBER (ID, FK_GROUP_ID, FK_USER_ID, MEMBERSHIP_ROLE, CREA
 (1, 1, 2, 'ADMIN', NOW(),  NOW()),
 (2, 1, 3, 'ADMIN', NOW(),  NOW()),
 (3, 1, 4, 'ADMIN', NOW(),  NOW());
+
+insert into SMP_DOMAIN_MEMBER (ID, FK_DOMAIN_ID, FK_USER_ID, MEMBERSHIP_ROLE, CREATED_ON, LAST_UPDATED_ON) values
+(1, 1, 1, 'ADMIN', NOW(),  NOW()),
+(2, 1, 2, 'VIEWER', NOW(),  NOW());
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java
index 24d983336..2f914ad1b 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationService.java
@@ -1,7 +1,9 @@
 package eu.europa.ec.edelivery.smp.auth;
 
 import eu.europa.ec.edelivery.smp.auth.enums.SMPUserAuthenticationTypes;
+import eu.europa.ec.edelivery.smp.data.dao.DomainMemberDao;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
+import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
 import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority;
@@ -21,9 +23,11 @@ import org.springframework.stereotype.Service;
 
 import java.net.URL;
 import java.time.OffsetDateTime;
+import java.util.Collections;
 import java.util.stream.Collectors;
 
-import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.*;
+import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN;
+import static eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority.S_AUTHORITY_TOKEN_USER;
 
 /**
  * @author Sebastian-Ion TINCU
@@ -34,6 +38,7 @@ public class SMPAuthorizationService {
     private static final String ERR_INVALID_OR_NULL = "Invalid or null authentication for the session!";
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPAuthorizationService.class);
 
+    DomainMemberDao domainMemberDao;
     private final ServiceGroupService serviceGroupService;
     private final ConversionService conversionService;
     private final ConfigurationService configurationService;
@@ -42,11 +47,13 @@ public class SMPAuthorizationService {
     public SMPAuthorizationService(ServiceGroupService serviceGroupService,
                                    ConversionService conversionService,
                                    ConfigurationService configurationService,
-                                   UserDao userDao) {
+                                   UserDao userDao,
+                                   DomainMemberDao domainMemberDao) {
         this.serviceGroupService = serviceGroupService;
         this.conversionService = conversionService;
         this.configurationService = configurationService;
         this.userDao = userDao;
+        this.domainMemberDao = domainMemberDao;
     }
 
     public boolean isSystemAdministrator() {
@@ -56,6 +63,18 @@ public class SMPAuthorizationService {
         return hasSystemRole;
     }
 
+    public boolean isDomainAdministrator(String domainEncId) {
+        SMPUserDetails userDetails = getAndValidateUserDetails();
+        Long domainId;
+        try {
+            domainId = SessionSecurityUtils.decryptEntityId(domainEncId);
+        } catch (SMPRuntimeException | NumberFormatException ex) {
+            LOG.error("Error occurred while decrypting domain-id:[" + domainEncId + "]", ex);
+            throw new BadCredentialsException("Login failed; Invalid userID or password");
+        }
+        return domainMemberDao.isUserDomainMemberWithRole(userDetails.getUser().getId(), Collections.singletonList(domainId), MembershipRoleType.ADMIN);
+    }
+
     public boolean isSMPAdministrator() {
         SMPUserDetails userDetails = getAndValidateUserDetails();
         boolean hasRole = hasSessionUserRole(S_AUTHORITY_TOKEN_USER, userDetails);
@@ -79,7 +98,7 @@ public class SMPAuthorizationService {
     public boolean isAuthorizedForManagingTheServiceMetadataGroup(Long serviceMetadataId) {
         SMPUserDetails userDetails = getAndValidateUserDetails();
         if (hasSessionUserRole(S_AUTHORITY_TOKEN_USER, userDetails)) {
-            LOG.debug("SMP admin is authorized to manage service metadata: [{}]" + serviceMetadataId);
+            LOG.debug("SMP admin is authorized to manage service metadata: [{}]" , serviceMetadataId);
             return true;
 
         }
@@ -154,7 +173,7 @@ public class SMPAuthorizationService {
         // set cas authentication data
         if (configurationService.getUIAuthenticationTypes().contains(SMPUserAuthenticationTypes.SSO.name())) {
             URL casUrlData = configurationService.getCasUserDataURL();
-            userRO.setCasUserDataUrl(casUrlData!=null?casUrlData.toString():null);
+            userRO.setCasUserDataUrl(casUrlData != null ? casUrlData.toString() : null);
         }
 
         return sanitize(userRO);
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
index 4db2ba11e..80dfb192e 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
@@ -37,6 +37,7 @@ public class ResourceConstants {
     // parameters
     public static final String PARAM_PAGINATION_PAGE="page";
     public static final String PARAM_PAGINATION_PAGE_SIZE="pageSize";
+    public static final String PARAM_PAGINATION_FILTER="filter";
     public static final String PARAM_PAGINATION_ORDER_BY="orderBy";
     public static final String PARAM_PAGINATION_ORDER_TYPE="orderType";
 
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DomainResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DomainResource.java
index fa1beb097..579ad68b9 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DomainResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/DomainResource.java
@@ -1,16 +1,17 @@
 package eu.europa.ec.edelivery.smp.ui.external;
 
 
+import eu.europa.ec.edelivery.smp.data.enums.MembershipRoleType;
 import eu.europa.ec.edelivery.smp.data.ui.DomainPublicRO;
+import eu.europa.ec.edelivery.smp.data.ui.MemberRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ui.UIDomainPublicService;
+import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.util.MimeTypeUtils;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*;
 
@@ -26,14 +27,16 @@ public class DomainResource {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DomainResource.class);
 
-    private UIDomainPublicService uiDomainService;
+    private final UIDomainPublicService uiDomainService;
+
 
     public DomainResource(UIDomainPublicService uiDomainService) {
         this.uiDomainService = uiDomainService;
+
     }
 
     @GetMapping(produces = {MimeTypeUtils.APPLICATION_JSON_VALUE})
-    public ServiceResult<DomainPublicRO> geDomainList(
+    public ServiceResult<DomainPublicRO> getDomainList(
             @RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page,
             @RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize,
             @RequestParam(value = PARAM_PAGINATION_ORDER_BY, required = false) String orderBy,
@@ -45,4 +48,50 @@ public class DomainResource {
         return result;
     }
 
+
+    @GetMapping(path = "/{user-enc-id}/{domain-enc-id}/members", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId)")
+    public ServiceResult<MemberRO> getDomainMemberList(
+            @PathVariable("user-enc-id") String userEncId,
+            @PathVariable("domain-enc-id") String domainEncId,
+            @RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page,
+            @RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize,
+            @RequestParam(value = PARAM_PAGINATION_FILTER, defaultValue = "", required = false) String filter) {
+
+        LOG.info("Search for domain members with filter  [{}], paging: [{}/{}], user: {}",filter,  page, pageSize, userEncId);
+        Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId);
+        return uiDomainService.getDomainMembers(domainId, page, pageSize,  filter);
+    }
+
+    @PutMapping(path = "/{user-enc-id}/{domain-enc-id}/member", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and (@smpAuthorizationService.systemAdministrator or @smpAuthorizationService.isDomainAdministrator(#domainEncId))")
+    public MemberRO  putDomainMember(
+            @PathVariable("user-enc-id") String userEncId,
+            @PathVariable("domain-enc-id") String domainEncId,
+            @RequestBody MemberRO memberRO) {
+
+        LOG.info("add member to domain");
+        Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId);
+        Long memberId = memberRO.getMemberId() == null?null: SessionSecurityUtils.decryptEntityId(memberRO.getMemberId());
+        if (memberRO.getRoleType() == null) {
+            memberRO.setRoleType(MembershipRoleType.VIEWER);
+        }
+        // is user domain admin or system admin
+        return uiDomainService.addMemberToDomain(domainId, memberRO, memberId);
+    }
+
+    @DeleteMapping(value = "/{user-enc-id}/{domain-enc-id}/member/{member-enc-id}/delete")
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and (@smpAuthorizationService.systemAdministrator or @smpAuthorizationService.isDomainAdministrator(#domainEncId))")
+    public MemberRO  deleteDomainMember(
+            @PathVariable("user-enc-id") String userEncId,
+            @PathVariable("domain-enc-id") String domainEncId,
+            @PathVariable("member-enc-id") String memberEncId
+            ) {
+        LOG.info("Delete member from domain");
+        Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId);
+        Long memberId= SessionSecurityUtils.decryptEntityId(memberEncId);
+
+        // is user domain admin or system admin
+        return uiDomainService.deleteMemberFromDomain(domainId, memberId);
+    }
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java
index ead3d8315..d60307bd8 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/UserResource.java
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_USER;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.PARAM_PAGINATION_FILTER;
 import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntityId;
 
 /**
@@ -74,6 +75,17 @@ public class UserResource {
         return result != null;
     }
 
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userId)")
+    @GetMapping(path = "/{user-id}/search", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    public List<SearchUserRO> lookupUsers(@PathVariable("user-id") String userId,
+                              @RequestParam(value = PARAM_PAGINATION_FILTER, defaultValue = "", required = false) String filter ) {
+        Long entityId = decryptEntityId(userId);
+        LOG.info("Validating the password of the currently logged in user:[{}] with id:[{}] ", userId, entityId);
+
+        //  return first 10 results
+        return  uiUserService.searchUsers(0, 10, filter).getServiceEntities();
+    }
+
     /**
      * Update the details of the currently logged-in user (e.g. update the role, the credentials or add certificate details).
      *
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationServiceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationServiceTest.java
index ba7442b02..0abc6d06e 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationServiceTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/auth/SMPAuthorizationServiceTest.java
@@ -1,5 +1,6 @@
 package eu.europa.ec.edelivery.smp.auth;
 
+import eu.europa.ec.edelivery.smp.data.dao.DomainMemberDao;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
 import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
@@ -33,9 +34,10 @@ public class SMPAuthorizationServiceTest {
     ConversionService conversionService = Mockito.mock(ConversionService.class);
     ConfigurationService configurationService = Mockito.mock(ConfigurationService.class);
     UserDao userDao = Mockito.mock(UserDao.class);
+    DomainMemberDao domainMemberDao = Mockito.mock(DomainMemberDao.class);
 
     SMPAuthorizationService testInstance = new SMPAuthorizationService(serviceGroupService, conversionService,
-            configurationService, userDao);
+            configurationService, userDao, domainMemberDao);
 
 
     @Before
-- 
GitLab