From 9a920f6842971411e86479a4febf2958975f2873 Mon Sep 17 00:00:00 2001
From: RIHTARSIC Joze <joze.rihtarsic@ext.ec.europa.eu>
Date: Wed, 12 Apr 2023 18:59:41 +0200
Subject: [PATCH] Update user administration and add windows OS script for
 springboot

---
 smp-angular/src/app/app.module.ts             |  10 +-
 smp-angular/src/app/app.routes.ts             |  24 +-
 .../app/common/enums/application-role.enum.ts |   4 +
 .../enums}/member-type.enum.ts                |   0
 .../enums}/membership-role.enum.ts            |   0
 .../data-panel/data-panel.component.html      |   4 +-
 .../panels/data-panel/data-panel.component.ts |   1 +
 .../search-table/search-table-entity.model.ts |   2 +-
 .../search-table/search-table.component.ts    |  21 +-
 .../src/app/guards/authenticated.guard.ts     |  32 ---
 ...{auth.guard.ts => authentication.guard.ts} |   2 +-
 .../src/app/security/security.service.ts      |   2 +
 smp-angular/src/app/smp.constants.ts          |  26 +-
 .../domain-member-panel.component.html        |   9 +-
 .../domain-member-panel.component.ts          |  10 +-
 .../member-dialog/member-dialog.component.ts  |   4 +-
 .../domain-member-panel/member-ro.model.ts    |   4 +-
 .../domain-member-panel/membership.service.ts |   2 +-
 .../admin-users/admin-user.component.css      |  19 ++
 .../admin-users/admin-user.component.html     |  74 +++++
 .../admin-users/admin-user.component.ts       | 252 ++++++++++++++++++
 .../admin-users/admin-user.service.ts         |  74 +++++
 .../user-profile-panel.component.html         | 184 +++++++++++++
 .../user-profile-panel.component.scss         |  42 +++
 .../user-profile-panel.component.ts           | 231 ++++++++++++++++
 .../system-settings/user/user-controller.ts   |   5 +-
 .../user-details-dialog.component.ts          |   7 +-
 .../app/system-settings/user/user-ro.model.ts |  14 +-
 .../user-profile/user-profile.component.html  | 168 +-----------
 .../user-profile/user-profile.component.scss  |   2 +-
 .../user-profile/user-profile.component.ts    | 186 ++++---------
 .../app/window/toolbar/toolbar.component.html |  12 +-
 .../ec/edelivery/smp/data/dao/DomainDao.java  |  21 +-
 .../smp/data/dao/DomainMemberDao.java         |  11 +-
 .../ec/edelivery/smp/data/model/DBDomain.java |   8 +-
 .../edelivery/smp/data/model/user/DBUser.java |  50 ++++
 .../smp/services/ui/UIUserService.java        |  48 +++-
 .../edelivery/smp/data/dao/DomainDaoTest.java |  76 ++++++
 .../edelivery/smp/data/dao/TestUtilsDao.java  |  47 +++-
 smp-springboot/README.md                      |  26 +-
 .../smp/auth/SMPAuthorizationService.java     |  14 +
 .../smp/ui/external/UserResource.java         |  32 ++-
 .../smp/ui/internal/UserAdminResource.java    |  70 ++++-
 43 files changed, 1389 insertions(+), 441 deletions(-)
 create mode 100644 smp-angular/src/app/common/enums/application-role.enum.ts
 rename smp-angular/src/app/{system-settings/admin-domain/domain-member-panel/member-dialog => common/enums}/member-type.enum.ts (100%)
 rename smp-angular/src/app/{system-settings/admin-domain/domain-member-panel => common/enums}/membership-role.enum.ts (100%)
 delete mode 100644 smp-angular/src/app/guards/authenticated.guard.ts
 rename smp-angular/src/app/guards/{auth.guard.ts => authentication.guard.ts} (95%)
 create mode 100644 smp-angular/src/app/system-settings/admin-users/admin-user.component.css
 create mode 100644 smp-angular/src/app/system-settings/admin-users/admin-user.component.html
 create mode 100644 smp-angular/src/app/system-settings/admin-users/admin-user.component.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-users/admin-user.service.ts
 create mode 100644 smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.html
 create mode 100644 smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.scss
 create mode 100644 smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.ts
 create mode 100644 smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoTest.java

diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index dca9f8ac4..ca4b32bad 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -11,7 +11,6 @@ import {AlertComponent} from "./alert/alert.component";
 import {AlertMessageComponent} from './common/alert-message/alert-message.component';
 import {AlertMessageService} from './common/alert-message/alert-message.service';
 import {AppComponent} from './app.component';
-import {AuthenticatedGuard} from './guards/authenticated.guard';
 import {AuthorizedAdminGuard} from './guards/authorized-admin.guard';
 import {AuthorizedGuard} from './guards/authorized.guard';
 import {AutoFocusDirective} from "./common/directive/autofocus/auto-focus.directive";
@@ -134,6 +133,11 @@ import {
 } 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";
+import {AdminUserComponent} from "./system-settings/admin-users/admin-user.component";
+import {AdminUserService} from "./system-settings/admin-users/admin-user.service";
+import {
+  UserProfilePanelComponent
+} from "./system-settings/admin-users/user-settings-panel/user-profile-panel.component";
 
 
 @NgModule({
@@ -143,6 +147,7 @@ import {MembershipService} from "./system-settings/admin-domain/domain-member-pa
     AdminDomainComponent,
     AdminTruststoreComponent,
     AdminKeystoreComponent,
+    AdminUserComponent,
     AlertComponent,
     AlertMessageComponent,
     AppComponent,
@@ -204,6 +209,7 @@ import {MembershipService} from "./system-settings/admin-domain/domain-member-pa
     UserComponent,
     UserDetailsDialogComponent,
     UserProfileComponent,
+    UserProfilePanelComponent,
   ],
   imports: [
     BrowserAnimationsModule,
@@ -248,8 +254,8 @@ import {MembershipService} from "./system-settings/admin-domain/domain-member-pa
     AdminDomainService,
     AdminKeystoreService,
     AdminTruststoreService,
+    AdminUserService,
     AlertMessageService,
-    AuthenticatedGuard,
     AuthorizedAdminGuard,
     AuthorizedGuard,
     CertificateService,
diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts
index f0f264360..4d2de6730 100644
--- a/smp-angular/src/app/app.routes.ts
+++ b/smp-angular/src/app/app.routes.ts
@@ -1,13 +1,11 @@
 import {RouterModule, Routes} from '@angular/router';
 import {LoginComponent} from './login/login.component';
 import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
-import {ServiceGroupEditComponent} from './service-group-edit/service-group-edit.component';
-import {AuthenticatedGuard} from './guards/authenticated.guard';
 import {UserComponent} from './system-settings/user/user.component';
 import {AlertComponent} from "./alert/alert.component";
 import {PropertyComponent} from "./system-settings/property/property.component";
 import {UserProfileComponent} from "./user-settings/user-profile/user-profile.component";
-import {authGuard} from "./guards/auth.guard";
+import {authenticationGuard} from "./guards/authentication.guard";
 import {UserAccessTokensComponent} from "./user-settings/user-access-tokens/user-access-tokens.component";
 import {UserCertificatesComponent} from "./user-settings/user-certificates/user-certificates.component";
 import {ExtensionComponent} from "./system-settings/admin-extension/extension.component";
@@ -15,25 +13,29 @@ import {AdminTruststoreComponent} from "./system-settings/admin-truststore/admin
 import {AdminKeystoreComponent} from "./system-settings/admin-keystore/admin-keystore.component";
 import {AdminDomainComponent} from "./system-settings/admin-domain/admin-domain.component";
 import {dirtyDeactivateGuard} from "./guards/dirty.guard";
+import {AdminUserComponent} from "./system-settings/admin-users/admin-user.component";
 
 
 const appRoutes: Routes = [
 
   {path: '', component: ServiceGroupSearchComponent},
   {path: 'search', redirectTo: ''},
+  {path: 'login', component: LoginComponent},
   {
-    path: 'edit',
-    component: ServiceGroupEditComponent,
-    canActivate: [AuthenticatedGuard],
-    canDeactivate: [dirtyDeactivateGuard]
+    path: 'administration',
+    canActivateChild: [authenticationGuard],
+    children: [
+      {path: 'admin-domain', component: AdminDomainComponent, canDeactivate: [dirtyDeactivateGuard]},
+      {path: 'admin-group', component: UserComponent, canDeactivate: [dirtyDeactivateGuard]},
+      {path: 'admin-resource', component: PropertyComponent, canDeactivate: [dirtyDeactivateGuard]}
+    ]
   },
-  {path: 'login', component: LoginComponent},
   {
     path: 'system-settings',
-    canActivateChild: [authGuard],
+    canActivateChild: [authenticationGuard],
     children: [
       {path: 'domain', component: AdminDomainComponent, canDeactivate: [dirtyDeactivateGuard]},
-      {path: 'user', component: UserComponent, canDeactivate: [dirtyDeactivateGuard]},
+      {path: 'user', component: AdminUserComponent, canDeactivate: [dirtyDeactivateGuard]},
       {path: 'properties', component: PropertyComponent, canDeactivate: [dirtyDeactivateGuard]},
       {path: 'keystore', component: AdminKeystoreComponent, canDeactivate: [dirtyDeactivateGuard]},
       {path: 'truststore', component: AdminTruststoreComponent, canDeactivate: [dirtyDeactivateGuard]},
@@ -43,7 +45,7 @@ const appRoutes: Routes = [
   },
   {
     path: 'user-settings',
-    canActivateChild: [authGuard],
+    canActivateChild: [authenticationGuard],
     children: [
       {path: 'user-profile', component: UserProfileComponent, canDeactivate: [dirtyDeactivateGuard]},
       {path: 'user-access-token', component: UserAccessTokensComponent, canDeactivate: [dirtyDeactivateGuard]},
diff --git a/smp-angular/src/app/common/enums/application-role.enum.ts b/smp-angular/src/app/common/enums/application-role.enum.ts
new file mode 100644
index 000000000..f2b05c36d
--- /dev/null
+++ b/smp-angular/src/app/common/enums/application-role.enum.ts
@@ -0,0 +1,4 @@
+export enum ApplicationRoleEnum {
+  USER = 'USER',
+  SYSTEM_ADMIN = 'SYSTEM_ADMIN'
+}
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/common/enums/member-type.enum.ts
similarity index 100%
rename from smp-angular/src/app/system-settings/admin-domain/domain-member-panel/member-dialog/member-type.enum.ts
rename to smp-angular/src/app/common/enums/member-type.enum.ts
diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts b/smp-angular/src/app/common/enums/membership-role.enum.ts
similarity index 100%
rename from smp-angular/src/app/system-settings/admin-domain/domain-member-panel/membership-role.enum.ts
rename to smp-angular/src/app/common/enums/membership-role.enum.ts
diff --git a/smp-angular/src/app/common/panels/data-panel/data-panel.component.html b/smp-angular/src/app/common/panels/data-panel/data-panel.component.html
index 401712adb..84e0662ce 100644
--- a/smp-angular/src/app/common/panels/data-panel/data-panel.component.html
+++ b/smp-angular/src/app/common/panels/data-panel/data-panel.component.html
@@ -1,5 +1,5 @@
-<div class="panel smp-container-limited">
-  <div class="smp-column-label">
+<div class="panel"  [ngClass]="{ 'smp-container-limited': showTitle}">
+  <div *ngIf="showTitle" class="smp-column-label">
     <p>{{title}}</p>
     <div innerHTML={{text}}></div>
     <ng-container *ngTemplateOutlet="labelColumnContent"></ng-container>
diff --git a/smp-angular/src/app/common/panels/data-panel/data-panel.component.ts b/smp-angular/src/app/common/panels/data-panel/data-panel.component.ts
index fd7ab7b43..1e39b5fff 100644
--- a/smp-angular/src/app/common/panels/data-panel/data-panel.component.ts
+++ b/smp-angular/src/app/common/panels/data-panel/data-panel.component.ts
@@ -12,6 +12,7 @@ import {
 export class DataPanelComponent {
 
   @Input() title: string;
+  @Input() showTitle: boolean=true;
   @Input() text: string;
   @Input() labelColumnContent: TemplateRef<any>;
 
diff --git a/smp-angular/src/app/common/search-table/search-table-entity.model.ts b/smp-angular/src/app/common/search-table/search-table-entity.model.ts
index 10b37f09d..7f1d89cbd 100644
--- a/smp-angular/src/app/common/search-table/search-table-entity.model.ts
+++ b/smp-angular/src/app/common/search-table/search-table-entity.model.ts
@@ -3,7 +3,7 @@ import {EntityStatus} from '../model/entity-status.model';
 export interface SearchTableEntity {
   id?: number;
   index?: number;
-  status: EntityStatus;
+  status?: EntityStatus;
   deleted?: boolean;
 
   actionMessage?: string;
diff --git a/smp-angular/src/app/common/search-table/search-table.component.ts b/smp-angular/src/app/common/search-table/search-table.component.ts
index bead1e97d..53451841d 100644
--- a/smp-angular/src/app/common/search-table/search-table.component.ts
+++ b/smp-angular/src/app/common/search-table/search-table.component.ts
@@ -17,7 +17,7 @@ import {ConfirmationDialogComponent} from "../dialogs/confirmation-dialog/confir
 import {SearchTableValidationResult} from "./search-table-validation-result.model";
 import {ExtendedHttpClient} from "../../http/extended-http-client";
 import {Router} from "@angular/router";
-import {AuthenticatedGuard} from "../../guards/authenticated.guard";
+import {authenticationGuard} from "../../guards/authentication.guard";
 import ObjectUtils from "../utils/object-utils";
 
 @Component({
@@ -77,7 +77,7 @@ export class SearchTableComponent implements OnInit {
               protected alertService: AlertMessageService,
               private downloadService: DownloadService,
               public dialog: MatDialog,
-              private router: Router, private authenticatedGuard: AuthenticatedGuard) {
+              private router: Router) {
   }
 
   ngOnInit(): void {
@@ -243,11 +243,7 @@ export class SearchTableComponent implements OnInit {
 
 
   onNewButtonClicked() {
-    this.authenticatedGuard.canActivate(this.router.routerState.snapshot.root, this.router.routerState.snapshot).subscribe(authorized => {
-      if (authorized) {
         this.fireCreateNewEntityEvent();
-      }
-    })
   }
 
   fireCreateNewEntityEvent() {
@@ -267,11 +263,7 @@ export class SearchTableComponent implements OnInit {
   }
 
   onDeleteButtonClicked() {
-    this.authenticatedGuard.canActivate(this.router.routerState.snapshot.root, this.router.routerState.snapshot).subscribe(authorized => {
-      if (authorized) {
         this.fireDeleteEntityEvent();
-      }
-    })
   }
 
   fireDeleteEntityEvent() {
@@ -279,20 +271,11 @@ export class SearchTableComponent implements OnInit {
   }
 
   onDeleteRowActionClicked(row: SearchTableEntity) {
-    this.authenticatedGuard.canActivate(this.router.routerState.snapshot.root, this.router.routerState.snapshot).subscribe(authorized => {
-      if (authorized) {
         this.deleteSearchTableEntities([row]);
-      }
-    })
-
   }
 
   onEditButtonClicked() {
-    this.authenticatedGuard.canActivate(this.router.routerState.snapshot.root, this.router.routerState.snapshot).subscribe(authorized => {
-      if (authorized) {
         this.fireEditEntityEvent();
-      }
-    })
   }
 
   fireEditEntityEvent() {
diff --git a/smp-angular/src/app/guards/authenticated.guard.ts b/smp-angular/src/app/guards/authenticated.guard.ts
deleted file mode 100644
index 2772ce203..000000000
--- a/smp-angular/src/app/guards/authenticated.guard.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import {Injectable} from '@angular/core';
-import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
-import {SecurityService} from '../security/security.service';
-import {ReplaySubject} from 'rxjs';
-import {AlertMessageService} from "../common/alert-message/alert-message.service";
-
-/**
- * Authentication guard validates if user is logged in. If not it re
- */
-@Injectable()
-export class AuthenticatedGuard implements CanActivate {
-
-  constructor(private router: Router, private securityService: SecurityService, private alertService: AlertMessageService) {
-  }
-
-  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
-    const subject = new ReplaySubject<boolean>();
-    this.securityService.isAuthenticated(true).subscribe((isAuthenticated: boolean) => {
-      if(isAuthenticated) {
-        subject.next(true);
-      } else {
-        console.log("User session is not active")
-        // not logged in so redirect to login page with the return url
-        this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
-        subject.next(false);
-        this.alertService.error('You have been logged out because of inactivity or missing access permissions.', true);
-      }
-    });
-    return subject.asObservable();
-
-  }
-}
diff --git a/smp-angular/src/app/guards/auth.guard.ts b/smp-angular/src/app/guards/authentication.guard.ts
similarity index 95%
rename from smp-angular/src/app/guards/auth.guard.ts
rename to smp-angular/src/app/guards/authentication.guard.ts
index 4b8f9fc1e..d9bfd8769 100644
--- a/smp-angular/src/app/guards/auth.guard.ts
+++ b/smp-angular/src/app/guards/authentication.guard.ts
@@ -4,7 +4,7 @@ import {SecurityService} from "../security/security.service";
 import {AlertMessageService} from "../common/alert-message/alert-message.service";
 import {NavigationService} from "../window/sidenav/navigation-model.service";
 
-export const authGuard = () => {
+export const authenticationGuard = () => {
   const navigationService = inject(NavigationService);
   const securityService = inject(SecurityService);
   const alertService = inject(AlertMessageService);
diff --git a/smp-angular/src/app/security/security.service.ts b/smp-angular/src/app/security/security.service.ts
index cd2e49f07..2a14888d9 100644
--- a/smp-angular/src/app/security/security.service.ts
+++ b/smp-angular/src/app/security/security.service.ts
@@ -14,6 +14,8 @@ export class SecurityService {
 
   readonly LOCAL_STORAGE_KEY_CURRENT_USER = 'currentUser';
 
+
+
   constructor(
     private http: HttpClient,
     private alertService: AlertMessageService,
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index fcddea6f7..94438eac0 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -10,8 +10,10 @@ 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_RETRIEVE = 'retrieve';
+
+  public static readonly PATH_ACTION_SEARCH = 'search';
   public static readonly PATH_ACTION_UPDATE_RESOURCE_TYPES = 'update-resource-types';
 
   public static readonly PATH_ACTION_UPDATE_SML_INTEGRATION = 'update-sml-integration-data';
@@ -31,7 +33,7 @@ export class SmpConstants {
   // public endpoints
   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_SEARCH_SERVICE_GROUP = SmpConstants.REST_PUBLIC + SmpConstants.PATH_ACTION_SEARCH;
   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";
@@ -54,7 +56,7 @@ export class SmpConstants {
   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'
+  public static readonly REST_PUBLIC_USER_SEARCH = SmpConstants.REST_PUBLIC_USER + "/" + SmpConstants.PATH_PARAM_ENC_USER_ID + "/" + SmpConstants.PATH_ACTION_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';
@@ -104,12 +106,24 @@ export class SmpConstants {
   public static readonly REST_INTERNAL_PROPERTY_MANAGE = SmpConstants.REST_INTERNAL + 'property';
   public static readonly REST_INTERNAL_PROPERTY_VALIDATE = SmpConstants.REST_INTERNAL_PROPERTY_MANAGE + '/validate';
   public static readonly REST_INTERNAL_DOMAIN_VALIDATE_DELETE = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED + '/validate-delete';
-  public static readonly REST_INTERNAL_USER_MANAGE = SmpConstants.REST_INTERNAL + 'user';
+  public static readonly REST_INTERNAL_USER_MANAGE = SmpConstants.REST_INTERNAL + 'user' +'/' + SmpConstants.PATH_PARAM_ENC_USER_ID;
+
+  public static readonly REST_INTERNAL_USER_MANAGE_CREATE = SmpConstants.REST_INTERNAL_USER_MANAGE + '/' +  SmpConstants.PATH_ACTION_CREATE;
+  public static readonly REST_INTERNAL_USER_MANAGE_UPDATE = SmpConstants.REST_INTERNAL_USER_MANAGE + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID  +'/' +  SmpConstants.PATH_ACTION_UPDATE;
+  public static readonly REST_INTERNAL_USER_MANAGE_DELETE = SmpConstants.REST_INTERNAL_USER_MANAGE + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID  +'/' +  SmpConstants.PATH_ACTION_DELETE;
+
+  public static readonly INTERNAL_USER_MANAGE_SEARCH = SmpConstants.REST_INTERNAL_USER_MANAGE + '/' +SmpConstants.PATH_ACTION_SEARCH;
+
+  public static readonly REST_INTERNAL_USER_MANAGE_DATA = SmpConstants.REST_INTERNAL_USER_MANAGE
+    + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID + '/' + SmpConstants.PATH_ACTION_RETRIEVE;
+
+
+
   public static readonly REST_INTERNAL_USER_GENERATE_ACCESS_TOKEN = SmpConstants.REST_INTERNAL_USER_MANAGE +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + 'generate-access-token-for' + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID;
+    '/' + 'generate-access-token-for' + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID;
 
   public static readonly REST_INTERNAL_USER_CHANGE_PASSWORD = SmpConstants.REST_INTERNAL_USER_MANAGE +
-    '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + 'change-password-for' + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID;
+    '/' + 'change-password-for' + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID;
 
   public static readonly REST_INTERNAL_USER_VALIDATE_DELETE = `${SmpConstants.REST_INTERNAL_USER_MANAGE}/validate-delete`;
   public static readonly REST_INTERNAL_KEYSTORE_DEPRECATED = SmpConstants.REST_INTERNAL + 'keystore';
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
index 21ab9c182..bcbf9dfe2 100644
--- 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
@@ -18,14 +18,10 @@
           <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-container mat-elevation-z2">
       <div class="domain-member-loading-shade"
            *ngIf="isLoadingResults">
         <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
@@ -63,10 +59,7 @@
             <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}"
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
index 77ed57a39..b085e301d 100644
--- 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
@@ -11,8 +11,8 @@ 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";
+import {MembershipRoleEnum} from "../../../common/enums/membership-role.enum";
+import {MemberTypeEnum} from "../../../common/enums/member-type.enum";
 
 
 @Component({
@@ -28,15 +28,9 @@ export class DomainMemberPanelComponent implements BeforeLeaveGuard {
   domainForm: FormGroup;
 
   displayedColumns: string[] = ['username', 'fullName', 'roleType', 'memberOf'];
-
   data: MemberRo[] = [];
-
   selectedMember: MemberRo;
-
   filter: any = {};
-
-  filterName: string;
-
   resultsLength = 0;
   isLoadingResults = false;
   @ViewChild(MatPaginator) paginator: MatPaginator;
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
index ae0887867..eafbf60c8 100644
--- 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
@@ -1,13 +1,13 @@
 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 {MembershipRoleEnum} from "../../../../common/enums/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 {MemberTypeEnum} from "../../../../common/enums/member-type.enum";
 import {AlertMessageService} from "../../../../common/alert-message/alert-message.service";
 
 
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
index d42464599..762f7f04e 100644
--- 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
@@ -1,7 +1,7 @@
 
-import {MembershipRoleEnum} from "./membership-role.enum";
+import {MembershipRoleEnum} from "../../../common/enums/membership-role.enum";
 import {SearchTableEntity} from "../../../common/search-table/search-table-entity.model";
-import {MemberTypeEnum} from "./member-dialog/member-type.enum";
+import {MemberTypeEnum} from "../../../common/enums/member-type.enum";
 
 export interface MemberRo extends SearchTableEntity {
 
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
index 364f024dc..17a8531d0 100644
--- 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
@@ -9,7 +9,7 @@ import {AlertMessageService} from "../../../common/alert-message/alert-message.s
 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";
+import {MembershipRoleEnum} from "../../../common/enums/membership-role.enum";
 
 
 @Injectable()
diff --git a/smp-angular/src/app/system-settings/admin-users/admin-user.component.css b/smp-angular/src/app/system-settings/admin-users/admin-user.component.css
new file mode 100644
index 000000000..b65965b4b
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/admin-user.component.css
@@ -0,0 +1,19 @@
+
+#admin-user-panel {
+  display: flex;
+  flex-flow: column;
+  align-items: center;
+  height: 100%;
+  min-height: 600px;
+  padding: 0 2em;
+}
+#user-filter {
+  width: 100%;
+  padding-top: 1em;
+}
+
+
+#admin-user-table {
+  width: 100%;
+  padding-top: 1em;
+}
diff --git a/smp-angular/src/app/system-settings/admin-users/admin-user.component.html b/smp-angular/src/app/system-settings/admin-users/admin-user.component.html
new file mode 100644
index 000000000..09f488c7f
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/admin-user.component.html
@@ -0,0 +1,74 @@
+<div id="admin-user-panel">
+  <data-panel id="admin-user-data-panel"
+              title="System User administration"
+              text="System User administration panel is a tool for creating and removing users from DomiSMP"
+              [labelColumnContent]="searchUserPanel">
+    <user-profile-panel
+      [showDataPanelTitles] =false
+      [managedUserData]="managedUserData"
+      (onSaveUserEvent)="onSaveUserEvent($event)"
+      (onDiscardNew)="onDiscardNew()"
+      ></user-profile-panel>
+  </data-panel>
+</div>
+
+<ng-template #searchUserPanel>
+  <mat-form-field id="domain-filter">
+    <mat-label>Filter Users</mat-label>
+    <input matInput (keyup)="applyUserFilter($event)" placeholder="User name or full name" #inputUserFilter>
+  </mat-form-field>
+
+  <mat-toolbar>
+    <mat-toolbar-row class="mat-elevation-z5">
+      <button mat-raised-button
+              mat-flat-button color="primary"
+              (click)="onCreateUserClicked()"
+              >Create User
+      </button>
+
+      <button mat-raised-button
+              [disabled]="canNotDelete"
+              color="primary"
+              (click)="onDeleteSelectedUserClicked()">
+        <mat-icon>delete</mat-icon>
+        <span>Delete selected</span>
+      </button>
+    </mat-toolbar-row>
+  </mat-toolbar>
+  <table class="mat-elevation-z2" id="admin-domain-table" mat-table [dataSource]="userData" >
+    <ng-container matColumnDef="username">
+      <th mat-header-cell *matHeaderCellDef >Username</th>
+      <td mat-cell *matCellDef="let row" [matTooltip]="row.username">{{row.username}}</td>
+    </ng-container>
+
+    <ng-container matColumnDef="fullName">
+      <th mat-header-cell *matHeaderCellDef >Full name</th>
+      <td mat-cell *matCellDef="let row" [matTooltip]="row.username">{{row.fullName}}</td>
+    </ng-container>
+
+    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+    <tr mat-row *matRowDef="let odd = odd; let row; columns: displayedColumns;"
+        (click)="userSelected(row)"
+        [ngClass]="{'datatable-row-selected': row===selected,'datatable-row-odd': odd}"
+    ></tr>
+
+
+    <tr class="mat-row" *matNoDataRow>
+      <td *ngIf="inputUserFilter.value;else noDataFound" class="mat-cell" colspan="2">No users matching the filter
+        "{{inputUserFilter.value}}"
+      </td>
+      <ng-template #noDataFound>
+        <td class="mat-cell" colspan="2">No data</td>
+      </ng-template>
+    </tr>
+  </table>
+
+  <mat-paginator class="mat-elevation-z2" id="extension-paginator"
+                 [length]="resultsLength"
+                 (page)="onPageChanged($event)"
+                 [pageSize]="5"
+                 [pageSizeOptions]="[5, 10, 25]"
+                 [showFirstLastButtons]="true"
+                 aria-label="Select page"></mat-paginator>
+
+</ng-template>
diff --git a/smp-angular/src/app/system-settings/admin-users/admin-user.component.ts b/smp-angular/src/app/system-settings/admin-users/admin-user.component.ts
new file mode 100644
index 000000000..0068df9f7
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/admin-user.component.ts
@@ -0,0 +1,252 @@
+import {AfterViewInit, Component, ViewChild} from '@angular/core';
+import {MatPaginator, PageEvent} from "@angular/material/paginator";
+import {AlertMessageService} from "../../common/alert-message/alert-message.service";
+import {ConfirmationDialogComponent} from "../../common/dialogs/confirmation-dialog/confirmation-dialog.component";
+import {MatDialog, MatDialogConfig, MatDialogRef} from "@angular/material/dialog";
+import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard";
+import {CancelDialogComponent} from "../../common/dialogs/cancel-dialog/cancel-dialog.component";
+import {SearchUserRo} from "../admin-domain/domain-member-panel/member-dialog/search-user-ro.model";
+import {AdminUserService} from "./admin-user.service";
+import {TableResult} from "../admin-domain/domain-member-panel/table-result.model";
+import {finalize} from "rxjs/operators";
+import {UserRo} from "../user/user-ro.model";
+import {SecurityService} from "../../security/security.service";
+import {
+  PasswordChangeDialogComponent
+} from "../../common/dialogs/password-change-dialog/password-change-dialog.component";
+import {UserDetailsDialogMode} from "../user/user-details-dialog/user-details-dialog.component";
+import {ApplicationRoleEnum} from "../../common/enums/application-role.enum";
+
+
+@Component({
+  moduleId: module.id,
+  templateUrl: './admin-user.component.html',
+  styleUrls: ['./admin-user.component.css']
+})
+export class AdminUserComponent implements AfterViewInit, BeforeLeaveGuard {
+  displayedColumns: string[] = ['username', 'fullName'];
+
+  selected?: SearchUserRo;
+
+  managedUserData?: UserRo;
+
+  userData: SearchUserRo[];
+  filter: string;
+  resultsLength: number = 0;
+  isLoadingResults: boolean = false;
+
+
+  @ViewChild(MatPaginator) paginator: MatPaginator;
+
+  constructor(private adminUserService: AdminUserService,
+              private securityService: SecurityService,
+              private alertService: AlertMessageService,
+              private dialog: MatDialog) {
+
+
+  }
+
+  ngAfterViewInit() {
+    this.loadTableData();
+  }
+
+  onPageChanged(page: PageEvent) {
+    this.loadTableData();
+  }
+
+  applyUserFilter(event: Event) {
+    const filterValue = (event.target as HTMLInputElement).value;
+    if (this.filter === filterValue) {
+      return;
+    }
+    this.filter = filterValue;
+    this.loadTableData();
+  }
+
+  loadTableData() {
+
+    this.isLoadingResults = true;
+
+    this.adminUserService.getUsersObservable(this.filter, this.paginator.pageIndex, this.paginator.pageSize)
+      .pipe(
+        finalize(() => {
+          this.isLoadingResults = false;
+        }))
+      .subscribe((result: TableResult<SearchUserRo>) => {
+          this.userData = [...result.serviceEntities];
+          this.resultsLength = result.count;
+          this.isLoadingResults = false;
+        }
+      );
+  }
+
+
+  onCreateUserClicked() {
+    this.selected = null;
+    this.managedUserData = {
+      active: true,
+      username: "",
+      role: ApplicationRoleEnum.USER
+    }
+  }
+
+
+  onDiscardNew() {
+    this.selected = null;
+    this.managedUserData = null;
+  }
+
+  public userSelected(userSelected: SearchUserRo) {
+    if (this.selected === userSelected) {
+      return;
+    }
+    if (this.isDirty()) {
+      let canChangeTab = this.dialog.open(CancelDialogComponent).afterClosed().toPromise<boolean>();
+      canChangeTab.then((canChange: boolean) => {
+        if (canChange) {
+          this.selectAndRetrieveUserData(userSelected);
+        }
+      });
+    } else {
+      console.log("set selected 1 ");
+      this.selectAndRetrieveUserData(userSelected);
+    }
+  }
+
+
+  public selectAndRetrieveUserData(selectUser: SearchUserRo) {
+    // clear old data
+    this.managedUserData = null;
+    if (!selectUser) {
+      return;
+
+    }
+    this.adminUserService.getUserDataObservable(selectUser.userId).subscribe((user: UserRo) => {
+      if (user) {
+        this.managedUserData = user;
+        this.selected = selectUser;
+      }
+    }, (error) => {
+      this.alertService.error(error.error?.errorDescription)
+    });
+  }
+
+  onSaveUserEvent(user: UserRo) {
+    if (!user.userId) {
+      this.createUserData(user);
+    } else {
+      this.updateUserData(user);
+    }
+  }
+
+  updateUserData(user: UserRo) {
+    // change only allowed data
+    this.adminUserService.updateManagedUser(user).subscribe(user => {
+      if (user) {
+        this.selected = null;
+        this.managedUserData = null;
+        this.loadTableData();
+        this.alertService.success("User [" + user.username + "] updated!");
+      }
+    }, (error) => {
+      this.alertService.error(error.error?.errorDescription)
+    });
+  }
+
+  createUserData(user: UserRo) {
+    // change only allowed data
+    this.adminUserService.createManagedUser(user).subscribe(user => {
+      if (user) {
+        this.selected = null;
+        this.managedUserData = null;
+        this.loadTableData();
+        this.alertService.success("User [" + user.username + "] created!");
+      }
+    }, (error) => {
+      this.alertService.error(error.error?.errorDescription)
+    });
+  }
+
+  onDeleteSelectedUserClicked() {
+
+    this.dialog.open(ConfirmationDialogComponent, {
+      data: {
+        title: "Delete user " + this.managedUserData?.username + " from DomiSMP",
+        description: "Action will permanently delete user! Do you wish to continue?"
+      }
+    }).afterClosed().subscribe(result => {
+      if (result) {
+        this.deleteUser(this.managedUserData);
+      }
+    });
+  }
+
+  deleteUser(user: UserRo) {
+
+    // change only allowed data
+    this.adminUserService.deleteManagedUser(user).subscribe(user => {
+      if (user) {
+        this.selected = null;
+        this.managedUserData = null;
+        this.loadTableData();
+        this.alertService.success("User [" + user.username + "] deleted!");
+      }
+    }, (error) => {
+      this.alertService.error(error.error?.errorDescription)
+    });
+
+  }
+
+  changeUserPasswordEvent(user: UserRo) {
+    const formRef: MatDialogRef<any> = this.changePasswordDialog({
+      data: {
+        user: user,
+        adminUser: user.userId != this.securityService.getCurrentUser().userId
+      },
+    });
+    formRef.afterClosed().subscribe(result => {
+      if (result) {
+        //this.currentUserData.passwordExpireOn = result.passwordExpireOn;
+        //this.currentUserData = {...this.currentUserData}
+      }
+    });
+  }
+
+  public changePasswordDialog(config?: MatDialogConfig): MatDialogRef<PasswordChangeDialogComponent> {
+    return this.dialog.open(PasswordChangeDialogComponent, this.convertConfig(config));
+  }
+
+
+  private convertConfig(config) {
+    return (config && config.data)
+      ? {
+        ...config,
+        data: {
+          ...config.data,
+          mode: config.data.mode || (config.data.edit ? UserDetailsDialogMode.EDIT_MODE : UserDetailsDialogMode.NEW_MODE)
+        }
+      }
+      : config;
+  }
+
+  isDirty(): boolean {
+    return false;
+  }
+
+
+  isNew(): boolean {
+    return !this.selected && !this.selected?.userId
+  }
+
+  get canNotDelete(): boolean {
+    return !this.selected || this.isLoggedInUser
+  }
+
+  get editMode(): boolean {
+    return this.isDirty();
+  }
+
+  get isLoggedInUser() {
+    return this.securityService.getCurrentUser()?.userId == this.managedUserData?.userId
+  }
+}
diff --git a/smp-angular/src/app/system-settings/admin-users/admin-user.service.ts b/smp-angular/src/app/system-settings/admin-users/admin-user.service.ts
new file mode 100644
index 000000000..a445a542f
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/admin-user.service.ts
@@ -0,0 +1,74 @@
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs';
+import {HttpClient, HttpParams} from "@angular/common/http";
+import {SecurityService} from "../../security/security.service";
+import {AlertMessageService} from "../../common/alert-message/alert-message.service";
+import {SearchTableResult} from "../../common/search-table/search-table-result.model";
+import {User} from "../../security/user.model";
+import {TableResult} from "../admin-domain/domain-member-panel/table-result.model";
+import {MemberRo} from "../admin-domain/domain-member-panel/member-ro.model";
+import {SmpConstants} from "../../smp.constants";
+import {UserRo} from "../user/user-ro.model";
+
+
+@Injectable()
+export class AdminUserService {
+
+
+  constructor(
+    private http: HttpClient,
+    private securityService: SecurityService) {
+  }
+
+  getUsersObservable(filter: string, 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())
+      .set('filter', !filter ? "" : filter);
+
+    return this.http.get<TableResult<MemberRo>>(SmpConstants.INTERNAL_USER_MANAGE_SEARCH
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId), {params});
+  }
+
+  getUserDataObservable(userId: string): Observable<UserRo> {
+    let user = this.securityService.getCurrentUser();
+    if (!user) {
+      return null;
+    }
+    return this.http.get<UserRo>(SmpConstants.REST_INTERNAL_USER_MANAGE_DATA
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID, userId));
+  }
+
+  updateManagedUser(managedUser: UserRo): Observable<UserRo> {
+    let user = this.securityService.getCurrentUser();
+    if (!user) {
+      return null;
+    }
+    return this.http.post<UserRo>(SmpConstants.REST_INTERNAL_USER_MANAGE_UPDATE
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID, managedUser.userId), managedUser);
+  }
+
+  createManagedUser(managedUser: UserRo): Observable<UserRo> {
+    let user = this.securityService.getCurrentUser();
+    if (!user) {
+      return null;
+    }
+    return this.http.put<UserRo>(SmpConstants.REST_INTERNAL_USER_MANAGE_CREATE
+        .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId)
+      , managedUser);
+  }
+
+  deleteManagedUser(managedUser: UserRo): Observable<UserRo> {
+    let user = this.securityService.getCurrentUser();
+    if (!user) {
+      return null;
+    }
+    return this.http.delete<UserRo>(SmpConstants.REST_INTERNAL_USER_MANAGE_DELETE
+      .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, user.userId)
+      .replace(SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID, managedUser.userId));
+  }
+}
diff --git a/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.html b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.html
new file mode 100644
index 000000000..4450cc236
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.html
@@ -0,0 +1,184 @@
+<div id="user-profile-panel">
+  <form [formGroup]="userForm">
+    <data-panel title="Account"
+                [showTitle]="showDataPanelTitles"
+                text="Account data">
+      <div class="panel" *ngIf="isNewUser"><p style="font-weight: bold">Enter user and click 'Save' to create new user
+      </div>
+      <mat-form-field class="user-profile-pane-field">
+        <mat-label>Username</mat-label>
+        <input id="username_id" matInput placeholder="Username" formControlName="username" #username
+               maxlength="255" required
+               auto-focus-directive>
+      </mat-form-field>
+      <div style="display:flex; flex-direction: row;align-items: center">
+        <mat-form-field style="width:100%" class="user-profile-pane-field">
+          <mat-label>Application role</mat-label>
+          <mat-select placeholder="Application role for the user"
+                      formControlName="role"
+                      matTooltip="application role for the user."
+                      id="role_id" required>
+            <mat-option *ngFor="let role of applicationRoles"
+                        [value]="role.value">
+              {{role.key}}
+            </mat-option>
+          </mat-select>
+          <mat-hint> Chose member role</mat-hint>
+        </mat-form-field>
+
+        <mat-checkbox
+          id="active_id"
+          formControlName="active">Active</mat-checkbox>
+      </div>
+
+    </data-panel>
+
+    <data-panel title="User profile"
+                [showTitle]="showDataPanelTitles"
+                text="User profile data and settings">
+      <mat-form-field class="user-profile-pane-field">
+        <mat-label>E-Mail Address</mat-label>
+        <input id="emailAddress_id" matInput placeholder="EMail Address" formControlName="emailAddress"
+               maxlength="127">
+        <div
+          *ngIf="userForm.controls['emailAddress'].hasError('pattern') && userForm.controls['emailAddress'].touched"
+          class="has-error">Email is invalid!
+        </div>
+      </mat-form-field>
+      <mat-form-field class="user-profile-pane-field">
+        <mat-label>Full name (name and last name)</mat-label>
+        <input id="fullName_id" matInput placeholder="Full name" formControlName="fullName"
+               maxlength="127">
+      </mat-form-field>
+
+      <mat-form-field class="user-profile-pane-field">
+        <mat-label>Theme</mat-label>
+        <select id="smpTheme_id" matNativeControl
+                (change)="onThemeSelect($event.target.value)"
+                formControlName="smpTheme">
+          <option *ngFor="let item of themeItems" [value]="item.className">{{item.name}}</option>
+        </select>
+      </mat-form-field>
+      <div class="user-profile-pane-field" style="display:flex;flex-direction: row">
+        <mat-form-field style="flex-grow: 1">
+          <mat-label>Locale (Date/time formatting)</mat-label>
+          <select id="smpLocale_id" matNativeControl id="moment-locale"
+                  (change)="onLocaleSelect($event.target.value)"
+                  formControlName="smpLocale"
+          >
+            <option value="bg">Bulgarian</option>
+            <option value="cs">Czech</option>
+            <option value="da">Danish</option>
+            <option value="de">German</option>
+            <option value="el">Greek</option>
+            <option value="en">English</option>
+            <option value="es">Spanish</option>
+            <option value="et">Estonian</option>
+            <option value="fi">Finnish</option>
+            <option value="fr">French</option>
+            <option value="hr">Croatian</option>
+            <option value="hu">Hungarian</option>
+            <option value="it">Italian</option>
+            <option value="lt">Lithuanian</option>
+            <option value="lv">Latvian</option>
+            <option value="mt">Maltese</option>
+            <option value="nl">Dutch</option>
+            <option value="pl">Polish</option>
+            <option value="pt">Portuguese</option>
+            <option value="ro">Romanian</option>
+            <option value="sk">Slovak</option>
+            <option value="sl">Slovenian</option>
+            <option value="sv">Swedish</option>
+          </select>
+        </mat-form-field>
+        <!-- show example only for logged-in user-->
+        <mat-form-field style="flex-grow: 1" *ngIf="isUserDataLoggedInUserData">
+          <mat-label>Example of Date/time</mat-label>
+          <input id="exampleDate_id" matInput [ngxMatDatetimePicker]="picker" placeholder="Choose a date"
+                 [value]="currentDate"
+                 readonly>
+          <mat-datepicker-toggle matSuffix [for]="picker" style="visibility: hidden"></mat-datepicker-toggle>
+          <ngx-mat-datetime-picker #picker [showSpinners]="true" [showSeconds]="false" [stepHour]="1"
+                                   [stepMinute]="1" [stepSecond]="1"
+                                   [hideTime]="false"
+          >
+
+          </ngx-mat-datetime-picker>
+        </mat-form-field>
+      </div>
+      <!-- buttons  -->
+      <div id="user-profile-panel-toolbar" class="panel">
+        <button id="cancelButton_id" mat-raised-button (click)="onResetButtonClicked()" color="primary"
+                [disabled]="!resetButtonEnabled">
+          <mat-icon>refresh</mat-icon>
+          <span>Reset</span>
+        </button>
+        <button id="saveButton_id" mat-raised-button (click)="onSaveButtonClicked()" color="primary"
+                [disabled]="!submitButtonEnabled">
+          <mat-icon>save</mat-icon>
+          <span>Save</span>
+        </button>
+      </div>
+    </data-panel>
+  </form>
+  <form [formGroup]="userCredentialForm">
+    <data-panel *ngIf="true" title="Username/password credentials"
+                [showTitle]="showDataPanelTitles"
+                text="Reset username password for the UI login">
+      <div style="display: flex;flex-flow: row wrap;">
+        <mat-form-field style="flex-grow: 1">
+          <mat-label>Last set</mat-label>
+          <input id="passwordUpdatedOn_id" matInput placeholder="Last set"
+                 value="{{!userCredentialForm.get('passwordUpdatedOn').value?nullValue:userCredentialForm.get('passwordUpdatedOn').value | date:dateTimeFormat}}"
+                 maxlength="255" disabled>
+        </mat-form-field>
+
+        <mat-form-field style="flex-grow: 1">
+          <mat-label>Password expire on</mat-label>
+          <input id="passwordExpireOn_id"
+                 *ngIf="!!userCredentialForm.get('passwordExpireOn').value; else noPasswordExpirySet " matInput
+                 placeholder="Valid until"
+                 value="{{userCredentialForm.get('passwordExpireOn').value | date:dateTimeFormat}}"
+                 maxlength="255" disabled>
+          <ng-template #noPasswordExpirySet>
+            <input id="passwordExpireOnMessage_id" matInput placeholder="Valid until" style="color: red"
+                   matTooltip="Default password set by system admin! User must change password immediately!"
+                   value="Default or null password"
+                   maxlength="255" disabled>
+          </ng-template>
+        </mat-form-field>
+      </div>
+      <div style="display: flex;flex-flow: row wrap;">
+        <mat-form-field style="flex-grow: 2">
+          <mat-label>Seq. failed attempts</mat-label>
+          <input id="sequentialLoginFailureCount_id" matInput placeholder="Seq. failed attempts"
+                 [value]="userCredentialForm.controls['sequentialLoginFailureCount'].value"
+                 maxlength="255" disabled readonly>
+        </mat-form-field>
+        <mat-form-field style="flex-grow: 1">
+          <mat-label>Last failed attempt</mat-label>
+          <input id="lastFailedLoginAttempt_id" matInput placeholder="Last failed attempt"
+                 value="{{!userCredentialForm.get('lastFailedLoginAttempt').value?nullValue:userCredentialForm.get('lastFailedLoginAttempt').value | date:dateTimeFormat}}"
+                 maxlength="255" disabled>
+        </mat-form-field>
+      </div>
+      <div style="display: flex;flex-flow: row wrap;">
+        <mat-form-field style="flex-grow: 1">
+          <mat-label>Suspended until</mat-label>
+          <input id="suspendedUtil_id" matInput placeholder="Suspended until"
+                 value="{{!userCredentialForm.get('suspendedUtil').value?nullValue:userCredentialForm.get('suspendedUtil').value | date:dateTimeFormat}}"
+                 maxlength="255" disabled>
+        </mat-form-field>
+      </div>
+
+
+      <div id="user-password-reset-panel-toolbar" class="panel">
+        <button mat-flat-button color="primary" id="changePassword_id"
+                (click)="changeCurrentUserPassword()">
+          <span>Set/change password</span>
+        </button>
+      </div>
+    </data-panel>
+  </form>
+</div>
+
diff --git a/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.scss b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.scss
new file mode 100644
index 000000000..453a8c2bd
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.scss
@@ -0,0 +1,42 @@
+
+.smp-container-limited {
+  display: flex;
+  flex-flow: row;
+  gap: 10px;
+  align-items: center;
+
+  max-width: 1204px;
+  width: 1204px;
+  min-width: 120px;
+}
+
+.smp-column-data {
+  min-height: 100px;
+  flex: 1 1 60%;
+  display: flex;
+  flex-direction: column;
+  align-self: stretch;
+}
+
+.smp-data-panel-field {
+  width: 100% !important;
+}
+
+.smp-column-label {
+  padding-top: 2em;
+  min-height: 100px;
+  max-width: 40%;
+  flex: 1 1 40%;
+  display: flex;
+  flex-direction: column;
+  align-self: stretch;
+
+
+}
+.smp-column-label p {
+  border-bottom: 1px solid black;
+  margin: 0em 2em 2em 1em;
+  font-weight: bold;
+
+}
+
diff --git a/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.ts b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.ts
new file mode 100644
index 000000000..333ed1aac
--- /dev/null
+++ b/smp-angular/src/app/system-settings/admin-users/user-settings-panel/user-profile-panel.component.ts
@@ -0,0 +1,231 @@
+import {Component, ElementRef, EventEmitter, Input, Output, ViewChild,} from '@angular/core';
+import {SmpConstants} from "../../../smp.constants";
+import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
+import {CredentialRo} from "../../../security/credential.model";
+import {UserController} from "../../user/user-controller";
+import {SecurityService} from "../../../security/security.service";
+import {ThemeService} from "../../../common/theme-service/theme.service";
+import {AlertMessageService} from "../../../common/alert-message/alert-message.service";
+import {UserService} from "../../user/user.service";
+import {MatDialog} from "@angular/material/dialog";
+import {HttpClient} from "@angular/common/http";
+import {GlobalLookups} from "../../../common/global-lookups";
+import {DateAdapter} from "@angular/material/core";
+import {NgxMatDateAdapter} from "@angular-material-components/datetime-picker";
+import {UserRo} from "../../user/user-ro.model";
+import {ApplicationRoleEnum} from "../../../common/enums/application-role.enum";
+
+
+@Component({
+  selector: 'user-profile-panel',
+  templateUrl: './user-profile-panel.component.html',
+  styleUrls: ['./user-profile-panel.component.scss']
+})
+export class UserProfilePanelComponent {
+
+  @Output() onSaveUserEvent: EventEmitter<UserRo> = new EventEmitter();
+  @Output() onDiscardNew: EventEmitter<any> = new EventEmitter();
+  @Output() onChangeUserPasswordEvent: EventEmitter<UserRo> = new EventEmitter();
+
+
+  readonly emailPattern = '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}';
+  readonly dateFormat: string = 'yyyy-MM-dd HH:mm:ssZ';
+  readonly dateTimeFormat: string = SmpConstants.DATE_TIME_FORMAT;
+  readonly nullValue: string = SmpConstants.NULL_VALUE;
+
+  readonly applicationRoles = Object.keys(ApplicationRoleEnum).map(el => {
+    return {key: el, value: ApplicationRoleEnum[el]}
+  });
+
+
+  userForm: FormGroup;
+  userCredentialForm: FormGroup;
+  _managedUserData: UserRo;
+
+  currentDate: Date = new Date();
+
+  currentPwdCredential: CredentialRo;
+  userController: UserController;
+
+  @Input() showDataPanelTitles: boolean = true
+
+  @ViewChild('username', {static: false}) usernameField: ElementRef;
+
+
+  constructor(
+    private securityService: SecurityService,
+    private themeService: ThemeService,
+    private alertService: AlertMessageService,
+    private formBuilder: FormBuilder,
+    private userService: UserService,
+    private dialog: MatDialog,
+    private http: HttpClient,
+    private lookups: GlobalLookups,
+    private dateAdapter: DateAdapter<Date>,
+    private ngxMatDateAdapter: NgxMatDateAdapter<Date>) {
+
+    this.userController = new UserController(this.http, this.lookups, this.dialog);
+
+    // set empty form ! do not bind it to current object !
+    this.userForm = formBuilder.group({
+      // common values
+      'username': new FormControl({value: '', disabled: true}),
+      'role': new FormControl({value: '', disabled: true}),
+      'active': new FormControl({value: '', disabled: true}),
+      'emailAddress': new FormControl({value: '', disabled: false}, [Validators.pattern(this.emailPattern),
+        Validators.maxLength(255)]),
+      'fullName': new FormControl({value: '', disabled: false}),
+      'smpTheme': new FormControl({value: 'default_theme', disabled: false}),
+      'smpLocale': new FormControl({value: 'fr', disabled: false}),
+
+    });
+
+    this.userCredentialForm = formBuilder.group({
+      'passwordUpdatedOn': new FormControl({value: '', disabled: true}),
+      'passwordExpireOn': new FormControl({value: '', disabled: true}),
+      'sequentialLoginFailureCount': new FormControl({value: '0', disabled: true}),
+      'lastFailedLoginAttempt': new FormControl({value: '', disabled: true}),
+      'suspendedUtil': new FormControl({value: '', disabled: true}),
+    });
+  }
+
+
+  get managedUserData(): UserRo {
+    let userRo = {...this._managedUserData};
+    userRo.active = this.userForm.get('active').value;
+    userRo.username = this.userForm.get('username').value;
+    userRo.role = this.userForm.get('role').value;
+    userRo.emailAddress = this.userForm.get('emailAddress').value;
+    userRo.fullName = this.userForm.get('fullName').value;
+    userRo.smpTheme = this.userForm.get('smpTheme').value;
+    userRo.smpLocale = this.userForm.get('smpLocale').value;
+    return userRo;
+  }
+
+  @Input() set managedUserData(value: UserRo) {
+    this._managedUserData = value;
+
+    if (!!this._managedUserData) {
+      this.userForm.controls['username'].setValue(this._managedUserData.username);
+      this.userForm.controls['active'].setValue(this._managedUserData.active);
+      this.userForm.controls['role'].setValue(this._managedUserData.role);
+      this.userForm.controls['emailAddress'].setValue(this._managedUserData.emailAddress);
+      this.userForm.controls['fullName'].setValue(this._managedUserData.fullName);
+      this.userForm.controls['smpTheme'].setValue(!this._managedUserData.smpTheme ? 'default_theme' : this._managedUserData.smpTheme);
+      this.userForm.controls['smpLocale'].setValue(!this._managedUserData.smpLocale ? 'fr' : this._managedUserData.smpLocale);
+      // mark form as pristine
+      this.userForm.enable();
+      // disable fields
+      if (!this.isNewUser) {
+        this.userForm.controls['username'].disable();
+      } else {
+        this.setFocus();
+      }
+      if (this.isUserDataLoggedInUserData) {
+        this.userForm.controls['role'].disable();
+        this.userForm.controls['active'].disable();
+      }
+    } else {
+      this.userForm.controls['username'].setValue("");
+      this.userForm.controls['role'].setValue("");
+      this.userForm.controls['active'].setValue("false");
+      this.userForm.controls['emailAddress'].setValue("");
+      this.userForm.controls['fullName'].setValue("");
+      this.userForm.controls['smpTheme'].setValue('default_theme');
+      this.userForm.controls['smpLocale'].setValue('fr');
+      this.userForm.disable();
+    }
+    this.userForm.markAsPristine();
+  }
+
+
+
+  private updatePwdCredential(currentPwdCredential: CredentialRo) {
+    this.currentPwdCredential = {
+      ...currentPwdCredential
+    }
+    this.userCredentialForm.controls['passwordUpdatedOn'].setValue(this.currentPwdCredential.updatedOn);
+    this.userCredentialForm.controls['passwordExpireOn'].setValue(this.currentPwdCredential.expireOn);
+    this.userCredentialForm.controls['sequentialLoginFailureCount'].setValue(this.currentPwdCredential.sequentialLoginFailureCount);
+    this.userCredentialForm.controls['lastFailedLoginAttempt'].setValue(this.currentPwdCredential.lastFailedLoginAttempt);
+    this.userCredentialForm.controls['suspendedUtil'].setValue(this.currentPwdCredential.suspendedUtil);
+    // mark form as pristine
+    this.userCredentialForm.markAsPristine();
+  }
+
+
+  onSaveButtonClicked() {
+    this.onSaveUserEvent.emit(this.managedUserData);
+  }
+
+  onResetButtonClicked() {
+    if (this.isNewUser) {
+      this.onDiscardNew.emit();
+    }
+    this.userForm.reset(this._managedUserData);
+    if (this.isUserDataLoggedInUserData) {
+      this.themeService.persistTheme(this._managedUserData.smpTheme);
+      this.dateAdapter.setLocale(this._managedUserData.smpLocale);
+      this.ngxMatDateAdapter.setLocale(this._managedUserData.smpLocale);
+    }
+  }
+
+  changeCurrentUserPassword() {
+    this.onChangeUserPasswordEvent.emit(this._managedUserData)
+  }
+
+
+  get submitButtonEnabled(): boolean {
+    return this.userForm.valid && this.userForm.dirty;
+  }
+
+  get resetButtonEnabled(): boolean {
+    return this.userForm.dirty;
+  }
+
+  get safeRefresh(): boolean {
+    return true;
+  }
+
+
+  onThemeSelect(target: string) {
+    // save theme only for logged in user
+    if (this.isUserDataLoggedInUserData) {
+      this.themeService.persistTheme(target);
+    }
+
+  }
+
+  get themeItems() {
+    return this.themeService.themes;
+  }
+
+  onLocaleSelect(target: string) {
+    // save locale only for logged-in user
+    if (this.isUserDataLoggedInUserData) {
+      this.dateAdapter.setLocale(target);
+      this.ngxMatDateAdapter.setLocale(target);
+    }
+  }
+
+  isDirty(): boolean {
+    return this.userForm.dirty;
+  }
+
+  get isNewUser(): boolean {
+    return !this._managedUserData?.userId;
+  }
+
+  get canChangeRole ():boolean {
+    return !this.isUserDataLoggedInUserData
+  }
+
+  get isUserDataLoggedInUserData(){
+    return this.securityService.getCurrentUser()?.userId == this._managedUserData?.userId
+  }
+
+  public setFocus() {
+    setTimeout(() => this.usernameField.nativeElement.focus());
+  }
+
+}
diff --git a/smp-angular/src/app/system-settings/user/user-controller.ts b/smp-angular/src/app/system-settings/user/user-controller.ts
index 00b6456fc..ebf6103e1 100644
--- a/smp-angular/src/app/system-settings/user/user-controller.ts
+++ b/smp-angular/src/app/system-settings/user/user-controller.ts
@@ -11,6 +11,7 @@ import {HttpClient} from "@angular/common/http";
 import {CertificateRo} from "./certificate-ro.model";
 import {PasswordChangeDialogComponent} from "../../common/dialogs/password-change-dialog/password-change-dialog.component";
 import {AccessTokenGenerationDialogComponent} from "../../common/dialogs/access-token-generation-dialog/access-token-generation-dialog.component";
+import {ApplicationRoleEnum} from "../../common/enums/application-role.enum";
 
 
 export class UserController implements SearchTableController {
@@ -70,10 +71,10 @@ export class UserController implements SearchTableController {
       index: null,
       username: '',
       emailAddress: '',
-      role: '',
+      role: ApplicationRoleEnum.USER,
       active: true,
       status: EntityStatus.NEW,
-      statusPassword: EntityStatus.NEW
+
     }
   }
 
diff --git a/smp-angular/src/app/system-settings/user/user-details-dialog/user-details-dialog.component.ts b/smp-angular/src/app/system-settings/user/user-details-dialog/user-details-dialog.component.ts
index c36ca3258..20fa12941 100644
--- a/smp-angular/src/app/system-settings/user/user-details-dialog/user-details-dialog.component.ts
+++ b/smp-angular/src/app/system-settings/user/user-details-dialog/user-details-dialog.component.ts
@@ -24,6 +24,7 @@ import {UserController} from "../user-controller";
 import {HttpClient} from "@angular/common/http";
 import {CertificateDialogComponent} from "../../../common/dialogs/certificate-dialog/certificate-dialog.component";
 import {SmpConstants} from "../../../smp.constants";
+import {ApplicationRoleEnum} from "../../../common/enums/application-role.enum";
 
 @Component({
   selector: 'user-details-dialog',
@@ -124,7 +125,7 @@ export class UserDetailsDialogComponent {
         sequentialTokenLoginFailureCount: null,
         lastTokenFailedLoginAttempt: null,
         tokenSuspendedUtil: null,
-        role: '',
+        role: ApplicationRoleEnum.USER,
         encodedValue: '',
         crlUrl: '',
         status: EntityStatus.NEW,
@@ -388,10 +389,10 @@ export class UserDetailsDialogComponent {
       index: null,
       username: '',
       emailAddress: '',
-      role: '',
+      role: ApplicationRoleEnum.USER,
       active: true,
       status: EntityStatus.NEW,
-      statusPassword: EntityStatus.NEW
+
     }
   }
 
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 fbcfe70c9..81dbbce93 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
@@ -1,19 +1,25 @@
 import {SearchTableEntity} from '../../common/search-table/search-table-entity.model';
 import {CertificateRo} from './certificate-ro.model';
+import {ApplicationRoleEnum} from "../../common/enums/application-role.enum";
 
 export interface UserRo extends SearchTableEntity {
   userId?: string
   username: string;
   fullName?: string;
-  emailAddress: string;
+  emailAddress?: string;
+  smpTheme?: string;
+  smpLocale?: string;
+  role: ApplicationRoleEnum;
+  active: boolean;
+
+
+
   accessTokenId?: string;
   passwordExpireOn?:	Date;
   accessTokenExpireOn?:	Date;
-  role: string;
-  active: boolean;
+
   suspended?: boolean;
   certificate?: CertificateRo;
-  statusPassword: number;
   casUserDataUrl?: string;
   sequentialLoginFailureCount?:number;
   lastFailedLoginAttempt?: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 7b00ffa2d..e8986fd80 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,163 +1,7 @@
-<div id="user-profile-panel">
-  <form [formGroup]="userForm" >
-    <data-panel title="Account"
-                text="Account data">
-      <mat-form-field class="user-profile-pane-field">
-        <mat-label>Username</mat-label>
-        <input matInput placeholder="Username" formControlName="username"
-               id="username_id" maxlength="255">
-      </mat-form-field>
-      <mat-form-field class="user-profile-pane-field">
-        <mat-label>Role</mat-label>
-        <input matInput placeholder="role" formControlName="role"
-               id="Role" maxlength="255">
-      </mat-form-field>
-    </data-panel>
-
-    <data-panel title="User profile"
-                text="User profile data and settings">
-      <mat-form-field class="user-profile-pane-field">
-        <mat-label>E-Mail Address</mat-label>
-        <input matInput placeholder="EMail Address" formControlName="emailAddress"
-               id="emailAddress_id" maxlength="255">
-        <div
-          *ngIf="userForm.controls['emailAddress'].hasError('pattern') && userForm.controls['emailAddress'].touched"
-          class="has-error">Email is invalid!
-        </div>
-      </mat-form-field>
-      <mat-form-field class="user-profile-pane-field">
-        <mat-label>Full name (name and last name)</mat-label>
-        <input matInput placeholder="Full name" formControlName="fullName"
-               id="fullName" maxlength="255">
-      </mat-form-field>
-
-      <mat-form-field class="user-profile-pane-field">
-        <mat-label>Theme</mat-label>
-        <select matNativeControl
-                (change)="onThemeSelect($event.target.value)"
-                formControlName="smpTheme">
-          <option *ngFor="let item of themeItems" [value]="item.className">{{item.name}}</option>
-        </select>
-      </mat-form-field>
-      <div class="user-profile-pane-field" style="display:flex;flex-direction: row">
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Locale (Date/time formatting)</mat-label>
-          <select matNativeControl id="moment-locale"
-                  (change)="onLocaleSelect($event.target.value)"
-                  formControlName="smpLocale"
-          >
-            <option value="bg">Bulgarian</option>
-            <option value="cs">Czech</option>
-            <option value="da">Danish</option>
-            <option value="de">German</option>
-            <option value="el">Greek</option>
-            <option value="en">English</option>
-            <option value="es">Spanish</option>
-            <option value="et">Estonian</option>
-            <option value="fi">Finnish</option>
-            <option value="fr">French</option>
-            <option value="hr">Croatian</option>
-            <option value="hu">Hungarian</option>
-            <option value="it">Italian</option>
-            <option value="lt">Lithuanian</option>
-            <option value="lv">Latvian</option>
-            <option value="mt">Maltese</option>
-            <option value="nl">Dutch</option>
-            <option value="pl">Polish</option>
-            <option value="pt">Portuguese</option>
-            <option value="ro">Romanian</option>
-            <option value="sk">Slovak</option>
-            <option value="sl">Slovenian</option>
-            <option value="sv">Swedish</option>
-          </select>
-
-
-        </mat-form-field>
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Example of Date/time</mat-label>
-          <input matInput [ngxMatDatetimePicker]="picker" placeholder="Choose a date"
-                 [value]="currentDate"
-                 >
-          <mat-datepicker-toggle matSuffix [for]="picker" style="visibility: visible"></mat-datepicker-toggle>
-          <ngx-mat-datetime-picker #picker [showSpinners]="true" [showSeconds]="false" [stepHour]="1"
-                                   [stepMinute]="1" [stepSecond]="1"
-                                   [hideTime]="false"
-          >
-
-          </ngx-mat-datetime-picker>
-        </mat-form-field>
-      </div>
-      <!-- buttons  -->
-      <div id="user-profile-panel-toolbar" class="panel">
-        <button id="cancelButton" mat-raised-button (click)="onResetButtonClicked()" color="primary"
-                [disabled]="!resetButtonEnabled">
-          <mat-icon>refresh</mat-icon>
-          <span>Reset</span>
-        </button>
-        <button id="saveButton" mat-raised-button (click)="onSaveButtonClicked()" color="primary"
-                [disabled]="!submitButtonEnabled">
-          <mat-icon>save</mat-icon>
-          <span>Save</span>
-        </button>
-      </div>
-    </data-panel>
-  </form>
-  <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;">
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Last set</mat-label>
-          <input matInput placeholder="Last set"
-                 value="{{!userCredentialForm.get('passwordUpdatedOn').value?nullValue:userCredentialForm.get('passwordUpdatedOn').value | date:dateTimeFormat}}"
-                 maxlength="255" disabled>
-        </mat-form-field>
-
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Password expire on</mat-label>
-          <input *ngIf="!!userCredentialForm.get('passwordExpireOn').value; else noPasswordExpirySet " matInput
-                 placeholder="Valid until"
-                 value="{{userCredentialForm.get('passwordExpireOn').value | date:dateTimeFormat}}"
-                 maxlength="255" disabled>
-          <ng-template #noPasswordExpirySet>
-            <input matInput placeholder="Valid until" style="color: red"
-                   matTooltip="Default password set by system admin! User must change password immediately!"
-                   value="Default or null password"
-                   maxlength="255" disabled>
-          </ng-template>
-        </mat-form-field>
-      </div>
-      <div style="display: flex;flex-flow: row wrap;">
-        <mat-form-field style="flex-grow: 2">
-          <mat-label>Seq. failed attempts</mat-label>
-          <input matInput placeholder="Seq. failed attempts"
-                 [value]="userCredentialForm.controls['sequentialLoginFailureCount'].value"
-                 id="sequentialLoginFailureCount_id" maxlength="255" disabled readonly>
-        </mat-form-field>
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Last failed attempt</mat-label>
-          <input matInput placeholder="Last failed attempt"
-                 value="{{!userCredentialForm.get('lastFailedLoginAttempt').value?nullValue:userCredentialForm.get('lastFailedLoginAttempt').value | date:dateTimeFormat}}"
-                 maxlength="255" disabled>
-        </mat-form-field>
-      </div>
-      <div style="display: flex;flex-flow: row wrap;">
-        <mat-form-field style="flex-grow: 1">
-          <mat-label>Suspended until</mat-label>
-          <input matInput placeholder="Suspended until"
-                 value="{{!userCredentialForm.get('suspendedUtil').value?nullValue:userCredentialForm.get('suspendedUtil').value | date:dateTimeFormat}}"
-                 maxlength="255" disabled>
-        </mat-form-field>
-      </div>
-
-
-      <div id="user-password-reset-panel-toolbar" class="panel">
-        <button mat-flat-button color="primary" id="changePassword_id"
-                (click)="changeCurrentUserPassword()">
-          <span>Set/change password</span>
-        </button>
-      </div>
-    </data-panel>
-  </form>
-</div>
+<user-profile-panel id="user-profile-component-panel"
+                    #userProfilePanel
+                    (onSaveUserEvent)="onSaveUserEvent($event)"
+                    (onChangeUserPasswordEvent)="changeUserPasswordEvent($event)"
+                    [managedUserData]="currentUserData">
+</user-profile-panel>
 
diff --git a/smp-angular/src/app/user-settings/user-profile/user-profile.component.scss b/smp-angular/src/app/user-settings/user-profile/user-profile.component.scss
index 88930e9e4..55184ddc7 100644
--- a/smp-angular/src/app/user-settings/user-profile/user-profile.component.scss
+++ b/smp-angular/src/app/user-settings/user-profile/user-profile.component.scss
@@ -1,4 +1,4 @@
-#user-profile-panel {
+#user-profile-component-panel {
   display: flex;
   flex-flow: column;
   align-items: center;
diff --git a/smp-angular/src/app/user-settings/user-profile/user-profile.component.ts b/smp-angular/src/app/user-settings/user-profile/user-profile.component.ts
index a5b3fc42d..9bcf54826 100644
--- a/smp-angular/src/app/user-settings/user-profile/user-profile.component.ts
+++ b/smp-angular/src/app/user-settings/user-profile/user-profile.component.ts
@@ -1,184 +1,104 @@
-import {Component, Input,} from '@angular/core';
+import {Component, ViewChild,} from '@angular/core';
 import {SecurityService} from "../../security/security.service";
-import {AlertMessageService} from "../../common/alert-message/alert-message.service";
-import {FormBuilder, FormControl, FormGroup, Validators,} from "@angular/forms";
-import {ThemeService} from "../../common/theme-service/theme.service";
 import {User} from "../../security/user.model";
 import {UserService} from "../../system-settings/user/user.service";
-import {SmpConstants} from "../../smp.constants";
-import {MatDialog, MatDialogRef} from "@angular/material/dialog";
-import {UserController} from "../../system-settings/user/user-controller";
-import {HttpClient} from "@angular/common/http";
-import {GlobalLookups} from "../../common/global-lookups";
-import {CredentialRo} from "../../security/credential.model";
-import {DateAdapter} from "@angular/material/core";
-import {NgxMatDateAdapter} from "@angular-material-components/datetime-picker";
 import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard";
+import {UserRo} from "../../system-settings/user/user-ro.model";
+import {
+  UserProfilePanelComponent
+} from "../../system-settings/admin-users/user-settings-panel/user-profile-panel.component";
+import {MatDialog, MatDialogConfig, MatDialogRef} from "@angular/material/dialog";
+import {
+  PasswordChangeDialogComponent
+} from "../../common/dialogs/password-change-dialog/password-change-dialog.component";
+import {UserDetailsDialogMode} from "../../system-settings/user/user-details-dialog/user-details-dialog.component";
 
 
 @Component({
   templateUrl: './user-profile.component.html',
   styleUrls: ['./user-profile.component.scss']
 })
-export class UserProfileComponent implements  BeforeLeaveGuard{
+export class UserProfileComponent implements BeforeLeaveGuard {
 
-  readonly emailPattern = '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}';
-  readonly dateFormat: string = 'yyyy-MM-dd HH:mm:ssZ';
-  readonly dateTimeFormat: string = SmpConstants.DATE_TIME_FORMAT;
-  readonly nullValue: string = SmpConstants.NULL_VALUE;
-  userForm: FormGroup;
-  userCredentialForm: FormGroup;
-  currentUserData: User;
 
-  currentDate: Date = new Date();
-
-  currentPwdCredential: CredentialRo;
-  userController: UserController;
-  @Input() showActionButtons: boolean = true;
+  @ViewChild('userProfilePanel') userProfilePanel: UserProfilePanelComponent;
+  currentUserData: UserRo;
+  loggedInUser: User;
 
   constructor(
-    private securityService: SecurityService,
-    private themeService: ThemeService,
-    private alertService: AlertMessageService,
-    private formBuilder: FormBuilder,
     private userService: UserService,
-    private dialog: MatDialog,
-    private http: HttpClient,
-    private lookups: GlobalLookups,
-    private dateAdapter: DateAdapter<Date>,
-    private ngxMatDateAdapter: NgxMatDateAdapter<Date>) {
-
-    this.userController = new UserController(this.http, this.lookups, this.dialog);
-
-    // set empty form ! do not bind it to current object !
-    this.userForm = formBuilder.group({
-      // common values
-      'username': new FormControl({value: '', disabled: true}),
-      'role': new FormControl({value: '', disabled: true}),
-      'emailAddress': new FormControl({value: '', disabled: false}, [Validators.pattern(this.emailPattern),
-        Validators.maxLength(255)]),
-      'fullName': new FormControl({value: '', disabled: false}),
-      'smpTheme': new FormControl({value: 'default_theme', disabled: false}),
-      'smpLocale': new FormControl({value: 'fr', disabled: false}),
+    private securityService: SecurityService,
+    public dialog: MatDialog) {
 
-    });
 
-    this.userCredentialForm = formBuilder.group({
-      'passwordUpdatedOn': new FormControl({value: '', disabled: true}),
-      'passwordExpireOn': new FormControl({value: '', disabled: true}),
-      'sequentialLoginFailureCount': new FormControl({value: '0', disabled: true}),
-      'lastFailedLoginAttempt': new FormControl({value: '', disabled: true}),
-      'suspendedUtil': new FormControl({value: '', disabled: true}),
-    });
     userService.onProfileDataChangedEvent().subscribe(updatedUser => {
         this.updateUserData(updatedUser);
       }
     );
 
-    userService.onPwdCredentialsUpdateEvent().subscribe(pwdCredential => {
-        this.updatePwdCredential(pwdCredential);
-      }
-    );
-
-    userService.getUserPwdCredentialStatus();
-
-    this.updateUserData(securityService.getCurrentUser())
-  }
+    this.updateUserData(this.securityService.getCurrentUser())
 
-  private updateUserData(currentUser: User) {
-    this.currentUserData = {
-      ...currentUser
-    }
-
-    this.userForm.controls['username'].setValue(this.currentUserData.username);
-    this.userForm.controls['role'].setValue(this.currentUserData.role);
-    this.userForm.controls['emailAddress'].setValue(this.currentUserData.emailAddress);
-    this.userForm.controls['fullName'].setValue(this.currentUserData.fullName);
-    this.userForm.controls['smpTheme'].setValue(!this.currentUserData.smpTheme ? 'default_theme' : this.currentUserData.smpTheme);
-    this.userForm.controls['smpLocale'].setValue(!this.currentUserData.smpLocale ? 'fr' : this.currentUserData.smpLocale);
-
-    // set current user theme as persisted for the application
-    this.themeService.persistTheme(this.currentUserData.smpTheme);
-    // mark form as pristine
-    this.userForm.markAsPristine();
   }
 
-  private updatePwdCredential(currentPwdCredential: CredentialRo) {
-    this.currentPwdCredential = {
-      ...currentPwdCredential
-    }
-    this.userCredentialForm.controls['passwordUpdatedOn'].setValue(this.currentPwdCredential.updatedOn);
-    this.userCredentialForm.controls['passwordExpireOn'].setValue(this.currentPwdCredential.expireOn);
-    this.userCredentialForm.controls['sequentialLoginFailureCount'].setValue(this.currentPwdCredential.sequentialLoginFailureCount);
-    this.userCredentialForm.controls['lastFailedLoginAttempt'].setValue(this.currentPwdCredential.lastFailedLoginAttempt);
-    this.userCredentialForm.controls['suspendedUtil'].setValue(this.currentPwdCredential.suspendedUtil);
-    // mark form as pristine
-    this.userCredentialForm.markAsPristine();
+  private updateUserData(user: User) {
+    this.currentUserData = this.convert(user);
+    this.loggedInUser = user;
   }
 
-
-  onSaveButtonClicked() {
-    let userData = {...this.currentUserData};
-    userData.emailAddress = this.userForm.get('emailAddress').value;
-    userData.fullName = this.userForm.get('fullName').value;
-    userData.smpTheme = this.userForm.get('smpTheme').value;
-    userData.smpLocale = this.userForm.get('smpLocale').value;
+  onSaveUserEvent(user: UserRo) {
+    let userData: User = {...this.loggedInUser};
+    // change only allowed data
+    userData.emailAddress = user.emailAddress;
+    userData.fullName = user.fullName;
+    userData.smpTheme = user.smpTheme;
+    userData.smpLocale = user.smpLocale;
 
     this.userService.updateUser(userData);
+
   }
 
-  onResetButtonClicked() {
-    this.userForm.reset(this.currentUserData);
+  isDirty(): boolean {
+    return this.userProfilePanel.isDirty()
   }
 
-  changeCurrentUserPassword() {
-    const formRef: MatDialogRef<any> = this.userController.changePasswordDialog({
+  changeUserPasswordEvent(user: UserRo) {
+    const formRef: MatDialogRef<any> = this.changePasswordDialog({
       data: {
-        user: this.currentUserData,
+        user: user,
         adminUser: false
       },
     });
     formRef.afterClosed().subscribe(result => {
       if (result) {
         this.currentUserData.passwordExpireOn = result.passwordExpireOn;
-        this.userForm.controls['passwordExpireOn'].setValue(this.currentUserData.passwordExpireOn);
+        this.currentUserData = {...this.currentUserData}
       }
     });
-
   }
 
-
-  get submitButtonEnabled(): boolean {
-    return this.userForm.valid && this.userForm.dirty;
-  }
-
-  get resetButtonEnabled(): boolean {
-    return this.userForm.dirty;
-  }
-
-  get safeRefresh(): boolean {
-    return true;
-  }
-
-
-  onThemeSelect(target: string) {
-    this.themeService.persistTheme(target);
+  public changePasswordDialog(config?: MatDialogConfig): MatDialogRef<PasswordChangeDialogComponent> {
+    return this.dialog.open(PasswordChangeDialogComponent, this.convertConfig(config));
   }
 
-  get themeItems() {
-    return this.themeService.themes;
-  }
 
-  onLocaleSelect(target: string) {
-    console.log("set locale" + target)
-    this.dateAdapter.setLocale(target);
-    this.ngxMatDateAdapter.setLocale(target);
+  private convertConfig(config) {
+    return (config && config.data)
+      ? {
+        ...config,
+        data: {
+          ...config.data,
+          mode: config.data.mode || (config.data.edit ? UserDetailsDialogMode.EDIT_MODE : UserDetailsDialogMode.NEW_MODE)
+        }
+      }
+      : config;
   }
 
-  isDirty(): boolean {
-    return this.userForm.dirty;
+  private convert(user: User): UserRo {
+    return {
+      ...user,
+      active: true,
+      status: undefined,
+      statusPassword: 0
+    } as UserRo;
   }
-
-
-
 }
diff --git a/smp-angular/src/app/window/toolbar/toolbar.component.html b/smp-angular/src/app/window/toolbar/toolbar.component.html
index fc2701f0c..e21a663c4 100644
--- a/smp-angular/src/app/window/toolbar/toolbar.component.html
+++ b/smp-angular/src/app/window/toolbar/toolbar.component.html
@@ -10,7 +10,7 @@
         </div-->
       </div>
     <span class="window-toolbar-spacer"></span>
-    <a class="window-toolbar-item" *ngIf="!currentUser" [routerLink]="['/login']" (click)="clearWarning()"> Login </a>
+    <a id="login_id" class="window-toolbar-item" *ngIf="!currentUser" [routerLink]="['/login']" (click)="clearWarning()"> Login </a>
     <span class="window-toolbar-item" *ngIf="currentUser">{{currentUserRoleDescription}}: {{currentUser}}  </span>
     <button class="window-toolbar-item" [mat-menu-trigger-for]="settingsMenu" id="settingsmenu_id"
              matTooltip="Menu"  >
@@ -19,24 +19,24 @@
 
     <mat-menu x-position="before" #settingsMenu="matMenu">
       <div *ngIf="currentUser">
-        <button mat-menu-item id="currentuser_id" (click)="editCurrentUser()">
+        <button id="currentuser_id" mat-menu-item  (click)="editCurrentUser()">
           <mat-icon>person</mat-icon>
           <span>{{currentUser}}</span>
         </button>
-        <button *ngIf="isUserAuthPasswdEnabled" mat-menu-item id="changePassword_id"
+        <button id="changePassword_id"  *ngIf="isUserAuthPasswdEnabled" mat-menu-item
                 (click)="changeCurrentUserPassword()">
           <span>Change password</span>
         </button>
-        <button *ngIf="isUserAuthSSOEnabled" mat-menu-item id="showSSODetails_id"
+        <button  id="showSSODetails_id" *ngIf="isUserAuthSSOEnabled" mat-menu-item
                 (click)="openCurrentCasUserData()">
           <span>Open CAS user data</span>
         </button>
-        <button *ngIf="isWebServiceUserTokenAuthPasswdEnabled" mat-menu-item id="getAccessToken_id"
+        <button id="getAccessToken_id" *ngIf="isWebServiceUserTokenAuthPasswdEnabled" mat-menu-item
                 (click)="regenerateCurrentUserAccessToken()">
           <span>Generated access token</span>
         </button>
         <hr/>
-        <button mat-menu-item (click)="logout($event)" id="logout_id">
+        <button id="logout_id" mat-menu-item (click)="logout($event)">
           <mat-icon>power_settings_new</mat-icon>
           <span>Logout</span>
         </button>
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
index 36c852157..e7aa71ec4 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
@@ -24,6 +24,7 @@ import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
 import javax.persistence.TypedQuery;
 import javax.transaction.Transactional;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
@@ -112,23 +113,23 @@ public class DomainDao extends BaseDao<DBDomain> {
         return query.getSingleResult();
     }
 
-    public Long getDomainsByUserIdAndRolesCount(Long userId, List<MembershipRoleType> roleTypes) {
-        if (roleTypes.isEmpty()) {
-            return 0L;
-        }
+
+
+    public Long getDomainsByUserIdAndRolesCount(Long userId, MembershipRoleType ... roleTypes) {
+
+        List<MembershipRoleType> list  = Arrays.asList(roleTypes ==null || roleTypes.length==0 ?MembershipRoleType.values(): roleTypes);
         TypedQuery<Long> query = memEManager.createNamedQuery(QUERY_DOMAIN_BY_USER_ROLES_COUNT, Long.class);
         query.setParameter(PARAM_USER_ID, userId);
-        query.setParameter(PARAM_MEMBERSHIP_ROLES, roleTypes);
+        query.setParameter(PARAM_MEMBERSHIP_ROLES, list);
         return query.getSingleResult();
     }
 
-    public List<DBDomain> getDomainsByUserIdAndRoles(Long userId, List<MembershipRoleType> roleTypes) {
-        if (roleTypes.isEmpty()) {
-            return Collections.emptyList();
-        }
+    public List<DBDomain> getDomainsByUserIdAndRoles(Long userId, MembershipRoleType ... roleTypes) {
+        List<MembershipRoleType> list  = Arrays.asList(roleTypes ==null || roleTypes.length==0 ?MembershipRoleType.values(): roleTypes);
+
         TypedQuery<DBDomain> query = memEManager.createNamedQuery(QUERY_DOMAIN_BY_USER_ROLES, DBDomain.class);
         query.setParameter(PARAM_USER_ID, userId);
-        query.setParameter(PARAM_MEMBERSHIP_ROLES, roleTypes);
+        query.setParameter(PARAM_MEMBERSHIP_ROLES, list);
         return query.getResultList();
     }
 
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 e4740a158..fe4c8183e 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
@@ -34,6 +34,11 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
 @Repository
 public class DomainMemberDao extends BaseDao<DBDomainMember> {
 
+    private final DomainDao domainDao;
+
+    public DomainMemberDao(DomainDao domainDao) {
+        this.domainDao = domainDao;
+    }
 
     public boolean isUserDomainMember(DBUser user, DBDomain domain) {
         return isUserDomainsMember(user.getId(), Collections.singletonList(domain.getId()));
@@ -60,14 +65,14 @@ public class DomainMemberDao extends BaseDao<DBDomainMember> {
         return query.getResultList().stream().anyMatch(member -> member.getRole() == roleType);
     }
 
-    public boolean isUserDomainAdministrator(Long userId){
-        return false;
+    public boolean isUserAnyDomainAdministrator(Long userId){
+        return domainDao.getDomainsByUserIdAndRolesCount(userId, MembershipRoleType.ADMIN)>0;
     }
     public boolean isUserGroupAdministrator(Long userId){
         return false;
     }
 
-    public boolean isUserMemberAdministrator(Long userId){
+    public boolean isUserResourceAdministrator(Long userId){
         return false;
     }
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
index 49c3c4c7e..0ef298c85 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
@@ -42,11 +42,11 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
         query = "update SMP_DOMAIN set SIGNATURE_KEY_ALIAS=:alias " +
                 "WHERE SML_CLIENT_KEY_ALIAS IS null")
 
-@NamedQuery(name = QUERY_DOMAIN_BY_USER_ROLES_COUNT, query = "SELECT count(c) FROM DBDomain c JOIN DBDomainMember dm " +
-        "WHERE c.id = dm.domain.id and dm.role in (:membership_roles) and dm.user.id= :user_id")
+@NamedQuery(name = QUERY_DOMAIN_BY_USER_ROLES_COUNT, query = "SELECT count(c) FROM DBDomain c JOIN DBDomainMember dm ON c.id = dm.domain.id " +
+        " WHERE dm.role in (:membership_roles) and dm.user.id= :user_id")
 
-@NamedQuery(name = QUERY_DOMAIN_BY_USER_ROLES, query = "SELECT c FROM DBDomain c JOIN DBDomainMember dm " +
-        "WHERE c.id = dm.domain.id and dm.role in (:membership_roles) and dm.user.id= :user_id")
+@NamedQuery(name = QUERY_DOMAIN_BY_USER_ROLES, query = "SELECT c FROM DBDomain c JOIN DBDomainMember dm ON c.id = dm.domain.id " +
+        " WHERE dm.role in (:membership_roles) and dm.user.id= :user_id")
 
 @org.hibernate.annotations.Table(appliesTo = "SMP_DOMAIN", comment = "SMP can handle multiple domains. This table contains domain specific data")
 public class DBDomain extends BaseEntity {
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 f9fa64425..637a7581a 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
@@ -18,11 +18,14 @@ import eu.europa.ec.edelivery.smp.data.enums.ApplicationRoleType;
 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.DBUserDeleteValidation;
+import eu.europa.ec.edelivery.smp.data.model.doc.DBResource;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.annotations.GenericGenerator;
 import org.hibernate.envers.Audited;
 
 import javax.persistence.*;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
@@ -151,6 +154,37 @@ public class DBUser extends BaseEntity {
     @ColumnDescription(comment = "DomiSMP settings: locale for the user")
     private String smpLocale;
 
+
+    @OneToMany(
+            mappedBy = "user",
+            cascade = CascadeType.ALL,
+            orphanRemoval = true,
+            fetch = FetchType.LAZY
+    )
+    private List<DBCredential> userCredentials = new ArrayList<>();
+
+    @OneToMany(
+            mappedBy = "user",
+            cascade = CascadeType.ALL,
+            orphanRemoval = true,
+            fetch = FetchType.LAZY
+    )
+    private List<DBDomainMember> domainMembers = new ArrayList<>();
+    @OneToMany(
+            mappedBy = "user",
+            cascade = CascadeType.ALL,
+            orphanRemoval = true,
+            fetch = FetchType.LAZY
+    )
+    private List<DBGroupMember> groupMembers = new ArrayList<>();
+
+    @OneToMany(
+            mappedBy = "user",
+            cascade = CascadeType.ALL,
+            orphanRemoval = true,
+            fetch = FetchType.LAZY
+    )
+    private List<DBResourceMember> resourceMembers = new ArrayList<>();
     @Override
     public Long getId() {
         return id;
@@ -216,6 +250,22 @@ public class DBUser extends BaseEntity {
         this.smpLocale = smpLocale;
     }
 
+    public List<DBCredential> getUserCredentials() {
+        return userCredentials;
+    }
+
+    public List<DBDomainMember> getDomainMembers() {
+        return domainMembers;
+    }
+
+    public List<DBGroupMember> getGroupMembers() {
+        return groupMembers;
+    }
+
+    public List<DBResourceMember> getResourceMembers() {
+        return resourceMembers;
+    }
+
     @Override
     public String toString() {
         return "DBUser{" +
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 f5861488c..ce65b7b26 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
@@ -336,6 +336,53 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         dbUser.setSmpLocale(user.getSmpLocale());
     }
 
+    @Transactional
+    public void adminUpdateUserData(Long userId, UserRO user) {
+        DBUser dbUser = userDao.find(userId);
+        if (dbUser == null) {
+            LOG.error("Can not update user because user for id [{}] does not exist!", userId);
+            throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "UserId", "Can not find user id!");
+        }
+        LOG.debug("Update user [{}]: email [{}], fullname [{}], smp theme [{}]", user.getUsername(), user.getEmailAddress(), user.getFullName(), user.getSmpTheme());
+        // update user data by admin
+        dbUser.setActive(user.isActive());
+        dbUser.setApplicationRole(user.getRole());
+        dbUser.setEmailAddress(user.getEmailAddress());
+        dbUser.setFullName(user.getFullName());
+        dbUser.setSmpTheme(user.getSmpTheme());
+        dbUser.setSmpLocale(user.getSmpLocale());
+    }
+
+    @Transactional
+    public UserRO adminCreateUserData(UserRO user) {
+
+        Optional<DBUser> testUser = userDao.findUserByUsername(user.getUsername());
+        if (testUser.isPresent()) {
+            throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "CreateUser", "User with username ["+user.getUsername()+"] already exists!");
+        }
+        DBUser dbUser = new DBUser();
+        // update user data by admin
+        dbUser.setUsername(user.getUsername());
+        dbUser.setApplicationRole(user.getRole());
+        dbUser.setEmailAddress(user.getEmailAddress());
+        dbUser.setFullName(user.getFullName());
+        dbUser.setSmpTheme(user.getSmpTheme());
+        dbUser.setSmpLocale(user.getSmpLocale());
+        userDao.persistFlushDetach(dbUser);
+        return conversionService.convert(dbUser, UserRO.class);
+    }
+
+    @Transactional
+    public UserRO adminDeleteUserData(Long userId) {
+        DBUser dbUser = userDao.find(userId);
+        if (dbUser == null) {
+            LOG.error("Can not delete user because user for id [{}] does not exist!", userId);
+            throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "UserId", "Can not find user id!");
+        }
+        userDao.remove(dbUser);
+        return conversionService.convert(dbUser, UserRO.class);
+    }
+
     protected void createOrUpdateUser(UserRO userRO, OffsetDateTime passwordChange) {
         /*
         if (userRO.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
@@ -499,7 +546,6 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         ServiceResult<SearchUserRO> result = new ServiceResult<>();
         result.setPage(page);
         result.setPageSize(pageSize);
-        ;
         if (count < 1) {
             result.setCount(0L);
             return result;
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoTest.java
new file mode 100644
index 000000000..8524a9ee6
--- /dev/null
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoTest.java
@@ -0,0 +1,76 @@
+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 org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * The group of resources with shared resource management rights. The user with group admin has rights to create/delete
+ * resources for the group.
+ *
+ * @author Joze Rihtarsic
+ * @since 5.0
+ */
+public class DomainDaoTest extends AbstractBaseDao {
+
+    @Autowired
+    DomainDao testInstance;
+
+    @Before
+    public void prepareDatabase() {
+        // setup initial data!
+        testUtilsDao.clearData();
+        testUtilsDao.creatDomainMemberships();
+
+    }
+    @Test
+    public void getDomainsByUserIdAndRolesCount() {
+        // one for domain 1
+        Long cnt = testInstance.getDomainsByUserIdAndRolesCount(testUtilsDao.getUser1().getId(), MembershipRoleType.ADMIN);
+        assertEquals(1, cnt.intValue());
+
+        // one for domain 2
+        cnt = testInstance.getDomainsByUserIdAndRolesCount(testUtilsDao.getUser1().getId(), MembershipRoleType.VIEWER);
+        assertEquals(1, cnt.intValue());
+
+        // all
+        cnt = testInstance.getDomainsByUserIdAndRolesCount(testUtilsDao.getUser1().getId());
+        assertEquals(2, cnt.intValue());
+
+        // all
+        cnt = testInstance.getDomainsByUserIdAndRolesCount(testUtilsDao.getUser1().getId(),  MembershipRoleType.VIEWER,  MembershipRoleType.ADMIN);
+        assertEquals(2, cnt.intValue());
+    }
+
+    @Test
+    public void getDomainsByUserIdAndRoles() {
+        // one for domain 1
+        List<DBDomain> result = testInstance.getDomainsByUserIdAndRoles(testUtilsDao.getUser1().getId(), MembershipRoleType.ADMIN);
+        assertEquals(1, result.size());
+        assertEquals(testUtilsDao.getD1(), result.get(0));
+
+        // one for domain 2
+        result = testInstance.getDomainsByUserIdAndRoles(testUtilsDao.getUser1().getId(), MembershipRoleType.VIEWER);
+        assertEquals(1, result.size());
+        assertEquals(testUtilsDao.getD2(), result.get(0));
+
+        result = testInstance.getDomainsByUserIdAndRoles(testUtilsDao.getUser2().getId(), MembershipRoleType.VIEWER);
+        assertEquals(0, result.size());
+
+        result = testInstance.getDomainsByUserIdAndRoles(testUtilsDao.getUser1().getId());
+        assertEquals(2, result.size());
+
+        result = testInstance.getDomainsByUserIdAndRoles(testUtilsDao.getUser1().getId(), MembershipRoleType.VIEWER,  MembershipRoleType.ADMIN);
+        assertEquals(2, result.size());
+
+
+    }
+}
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java
index 1f9646785..ee1557a6f 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/TestUtilsDao.java
@@ -1,5 +1,6 @@
 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.DBDomainResourceDef;
 import eu.europa.ec.edelivery.smp.data.model.DBGroup;
@@ -9,6 +10,7 @@ import eu.europa.ec.edelivery.smp.data.model.doc.DBSubresource;
 import eu.europa.ec.edelivery.smp.data.model.ext.DBExtension;
 import eu.europa.ec.edelivery.smp.data.model.ext.DBResourceDef;
 import eu.europa.ec.edelivery.smp.data.model.ext.DBSubresourceDef;
+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.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
@@ -65,6 +67,9 @@ public class TestUtilsDao {
     DBSubresource subresourceD1G1RD1_S1;
     DBSubresource subresourceD2G1RD1_S1;
 
+    DBDomainMember domainMemberU1D1Admin;
+    DBDomainMember domainMemberU1D2Viewer;
+
     DBExtension extension;
 
     /**
@@ -93,7 +98,8 @@ public class TestUtilsDao {
         subresourceD2G1RD1_S1 = null;
         documentD1G1RD1_S1 = null;
         documentD2G1RD1_S1 = null;
-
+        domainMemberU1D1Admin = null;
+        domainMemberU1D2Viewer = null;
         extension = null;
     }
 
@@ -188,6 +194,37 @@ public class TestUtilsDao {
         assertNotNull(user3.getId());
     }
 
+    /**
+     * Create domain members for
+     * user1 on domain 1  as Admin
+     * user1 on domain 2  as Viewer
+     */
+    @Transactional
+    public void creatDomainMemberships() {
+        if (domainMemberU1D1Admin != null) {
+            LOG.trace("DomainMemberships are already initialized!");
+            return;
+        }
+        createDomains();
+        createUsers();
+        domainMemberU1D1Admin = createDomainMembership(MembershipRoleType.ADMIN, user1, d1);
+        domainMemberU1D2Viewer = createDomainMembership(MembershipRoleType.VIEWER, user1, d2);
+
+        persistFlushDetach(domainMemberU1D1Admin);
+        persistFlushDetach(domainMemberU1D2Viewer);
+
+        assertNotNull(domainMemberU1D1Admin.getId());
+        assertNotNull(domainMemberU1D2Viewer.getId());
+    }
+
+    public DBDomainMember createDomainMembership(MembershipRoleType roleType, DBUser user, DBDomain domain){
+        DBDomainMember domainMember = new DBDomainMember();
+        domainMember.setRole(roleType);
+        domainMember.setUser(user);
+        domainMember.setDomain(domain);
+        return domainMember;
+    }
+
     /**
      * Create resources for ids:
      * TEST_SG_ID_1, TEST_SG_ID_2
@@ -470,4 +507,12 @@ public class TestUtilsDao {
     public DBExtension getExtension() {
         return extension;
     }
+
+    public DBDomainMember getDomainMemberU1D1Admin() {
+        return domainMemberU1D1Admin;
+    }
+
+    public DBDomainMember getDomainMemberU1D2Viewer() {
+        return domainMemberU1D2Viewer;
+    }
 }
diff --git a/smp-springboot/README.md b/smp-springboot/README.md
index 966025b15..c881a3f21 100644
--- a/smp-springboot/README.md
+++ b/smp-springboot/README.md
@@ -57,7 +57,7 @@ The script connect to mysql database using CLI tool 'mysql' and  deletes databas
 and insert the init data from
 [PROJECT_HOME]/smp-soapui-tests/src/test/resources/init-data/init-test-mysql-soapui.sql
 
-
+Linux OS:
 ```
 #!/bin/sh
  
@@ -80,6 +80,30 @@ echo "init database for soapui tests"
 mysql -h localhost -u $DB_ADMIN --password=$DB_ADMIN_PASSWORD $DATABASE < "$PROJECT_HOME/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql"
 ```
 
+Windows OS:
+```
+@echo off
+
+
+set PROJECT_HOME=C:\cef\code\smp
+set DATABASE=smpdb
+set DB_ADMIN=root
+set DB_ADMIN_PASSWORD=
+set DB_USERNAME=smp
+set DB_PASSWORD=smp
+
+REM recreate database
+echo "clean the database %DATABASE% if exists "
+mysql -h localhost -u %DB_ADMIN% --password=%DB_ADMIN_PASSWORD% -e "drop schema if exists %DATABASE%;DROP USER IF EXISTS %DB_USERNAME%;create schema %DATABASE%;alter database %DATABASE% charset=utf8;create user %DB_USERNAME% identified by '%DB_PASSWORD%';grant all on %DATABASE%.* to %DB_USERNAME%;"
+
+
+REM create new database
+echo "create database"
+mysql -h localhost -u %DB_ADMIN% --password=%DB_ADMIN_PASSWORD% %DATABASE% < "%PROJECT_HOME%\smp-webapp\src\main\smp-setup\database-scripts\mysql5innodb.ddl"
+echo "init database for soapui tests"
+mysql -h localhost -u %DB_ADMIN% --password=%DB_ADMIN_PASSWORD% %DATABASE% < "%PROJECT_HOME%\smp-soapui-tests\groovy\mysql-4.1_integration_test_data.sql"
+```
+
 ### Prepare the DomiSMP database configuration.
 
 To set the  DomiSMP database configuration, the following properties must be set.
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 2f914ad1b..0684a30b2 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
@@ -75,6 +75,20 @@ public class SMPAuthorizationService {
         return domainMemberDao.isUserDomainMemberWithRole(userDetails.getUser().getId(), Collections.singletonList(domainId), MembershipRoleType.ADMIN);
     }
 
+    public boolean isAnyDomainAdministrator() {
+        SMPUserDetails userDetails = getAndValidateUserDetails();
+        return domainMemberDao.isUserAnyDomainAdministrator(userDetails.getUser().getId());
+    }
+
+    public boolean isAnyGroupAdministrator() {
+        SMPUserDetails userDetails = getAndValidateUserDetails();
+        return domainMemberDao.isUserGroupAdministrator(userDetails.getUser().getId());
+    }
+    public boolean isAnyResourceAdministrator() {
+        SMPUserDetails userDetails = getAndValidateUserDetails();
+        return domainMemberDao.isUserResourceAdministrator(userDetails.getUser().getId());
+    }
+
     public boolean isSMPAdministrator() {
         SMPUserDetails userDetails = getAndValidateUserDetails();
         boolean hasRole = hasSessionUserRole(S_AUTHORITY_TOKEN_USER, userDetails);
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 4cd776192..7adbf5dfa 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
@@ -120,7 +120,11 @@ public class UserResource {
         DBUser user = uiUserService.findUser(entityId);
         NavigationTreeNodeRO home = new NavigationTreeNodeRO("home", "Home", "home", "");
         home.addChild(createPublicNavigationTreeNode());
-       // home.addChild(createEditNavigationTreeNode());
+        // create administration nodes for domains, groups and resources
+        NavigationTreeNodeRO adminNodes = createEditNavigationTreeNode();
+        if (!adminNodes.getChildren().isEmpty()) {
+            home.addChild(adminNodes);
+        }
         if (user.getApplicationRole() == ApplicationRoleType.SYSTEM_ADMIN) {
             home.addChild(createSystemAdminNavigationTreeNode());
         }
@@ -252,7 +256,7 @@ public class UserResource {
     protected NavigationTreeNodeRO createPublicNavigationTreeNode() {
         NavigationTreeNodeRO node = new NavigationTreeNodeRO("search-tools", "Search", "search", "public");
         node.addChild(new NavigationTreeNodeRO("search-resources", "Resources", "find_in_page", "search-resource","Search registered resources"));
-  //      node.addChild(new NavigationTreeNodeRO("search-lookup", "DNS lookup", "dns", "dns-lookup" , "DNS lookup tools"));
+        node.addChild(new NavigationTreeNodeRO("search-lookup", "DNS lookup", "dns", "dns-lookup" , "DNS lookup tools"));
         return node;
     }
 
@@ -267,29 +271,31 @@ public class UserResource {
 
     protected NavigationTreeNodeRO createSystemAdminNavigationTreeNode() {
         NavigationTreeNodeRO node = new NavigationTreeNodeRO("system-settings", "System settings", "admin_panel_settings", "system-settings");
+        node.addChild(new NavigationTreeNodeRO("system-admin-user", "Users", "people", "user"));
         node.addChild(new NavigationTreeNodeRO("system-admin-domain", "Domains", "domain", "domain"));
         node.addChild(new NavigationTreeNodeRO("system-admin-keystore", "Keystore", "key", "keystore"));
         node.addChild(new NavigationTreeNodeRO("system-admin-truststore", "Truststore", "article", "truststore"));
         node.addChild(new NavigationTreeNodeRO("system-admin-extension", "Extensions", "extension", "extension"));
-        node.addChild(new NavigationTreeNodeRO("system-admin-user", "Users", "people", "user"));
         node.addChild(new NavigationTreeNodeRO("system-admin-properties", "Properties", "properties", "properties"));
        // node.addChild(new NavigationTreeNodeRO("system-admin-authentication", "Authentication", "shield", "authentication"));
-
-
         node.addChild(new NavigationTreeNodeRO("system-admin-alert", "Alerts", "notifications", "alert"));
         return node;
     }
 
     protected NavigationTreeNodeRO createEditNavigationTreeNode() {
-        NavigationTreeNodeRO node = new NavigationTreeNodeRO("admin-entities", "Administration", "settings", "admin-entities");
+        NavigationTreeNodeRO node = new NavigationTreeNodeRO("administration", "Administration", "settings", "administration");
         // is domain admin
-
-        node.addChild(new NavigationTreeNodeRO("admin-domain", "Edit domains", "account_circle", "admin-domain"));
-        // is group admin
-        node.addChild(new NavigationTreeNodeRO("admin-group", "Edit groups", "key", "admin-group"));
-        // is resource admin
-        node.addChild(new NavigationTreeNodeRO("admin-resource", "Edit resources", "article", "admin-resource"));
-        //      node.addChild(new NavigationTreeNodeRO("user-data-membership", "Membership", "person", "user-membership"));
+        if (authorizationService.isAnyDomainAdministrator()) {
+            node.addChild(new NavigationTreeNodeRO("admin-domain", "Edit domains", "account_circle", "admin-domain"));
+        }
+        if (authorizationService.isAnyGroupAdministrator()) {
+            // is group admin
+            node.addChild(new NavigationTreeNodeRO("admin-group", "Edit groups", "key", "admin-group"));
+        }
+        if (authorizationService.isAnyResourceAdministrator()) {
+            // is resource admin
+            node.addChild(new NavigationTreeNodeRO("admin-resource", "Edit resources", "article", "admin-resource"));
+        }
         return node;
     }
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/UserAdminResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/UserAdminResource.java
index 6cb7cfd38..5a2d92eed 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/UserAdminResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/UserAdminResource.java
@@ -12,6 +12,7 @@ import eu.europa.ec.edelivery.smp.services.ui.UIUserService;
 import eu.europa.ec.edelivery.smp.services.ui.filters.UserFilter;
 import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
 import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.web.authentication.session.SessionAuthenticationException;
 import org.springframework.util.MimeTypeUtils;
 import org.springframework.web.bind.annotation.*;
@@ -20,7 +21,8 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_INTERNAL_USER;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*;
+import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.PARAM_PAGINATION_FILTER;
 import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntityId;
 
 /**
@@ -32,7 +34,6 @@ import static eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils.decryptEntit
 public class UserAdminResource {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UserAdminResource.class);
-
     protected UIUserService uiUserService;
     protected UITruststoreService uiTruststoreService;
     protected SMPAuthorizationService authorizationService;
@@ -60,6 +61,71 @@ public class UserAdminResource {
         return uiUserService.getTableList(page, pageSize, orderBy, orderType, filter);
     }
 
+    @GetMapping(path = "/{user-enc-id}/search", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
+    public ServiceResult<SearchUserRO> getDomainMemberList(
+            @PathVariable("user-enc-id") String userEncId,
+            @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 user with filter  [{}], paging: [{}/{}], user: {}",filter,  page, pageSize, userEncId);
+        return uiUserService.searchUsers(page, pageSize,  filter);
+    }
+
+    @GetMapping(path = "/{user-enc-id}/{managed-user-enc-id}/retrieve", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
+    public UserRO getUserData(@PathVariable("user-enc-id") String userEncId,
+                              @PathVariable("managed-user-enc-id") String managedUserEncId) {
+        Long managedUserId = decryptEntityId(managedUserEncId);
+        return uiUserService.getUserById(managedUserId);
+    }
+
+    @PostMapping(path = "/{user-enc-id}/{managed-user-enc-id}/update",  produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
+    public UserRO updateUser(@PathVariable("user-enc-id") String userEncId,
+                           @PathVariable("managed-user-enc-id") String managedUserEncId,
+                            @RequestBody UserRO user) {
+
+        Long userId = decryptEntityId(userEncId);
+        Long managedUserId = decryptEntityId(managedUserEncId);
+        LOG.info("UpdateUserData adminId: [{}], managedUserId: [{}]", userId, managedUserId);
+        // Update the user and mark the password as changed at this very instant of time
+        uiUserService.adminUpdateUserData(managedUserId, user);
+        // refresh user from DB
+        UserRO userRO = uiUserService.getUserById(managedUserId);
+        // return clean user to UI
+        return authorizationService.sanitize(userRO);
+    }
+
+
+    @DeleteMapping(path = "/{user-enc-id}/{managed-user-enc-id}/delete",  produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
+    public UserRO deleteUser(@PathVariable("user-enc-id") String userEncId,
+                           @PathVariable("managed-user-enc-id") String managedUserEncId) {
+
+        Long userId = decryptEntityId(userEncId);
+        Long managedUserId = decryptEntityId(managedUserEncId);
+        LOG.info("DeleteUserData adminId: [{}], managedUserId: [{}]", userId, managedUserId);
+        // Update the user and mark the password as changed at this very instant of time
+        UserRO deleted = uiUserService.adminDeleteUserData(managedUserId);
+        // return clean user to UI
+        return authorizationService.sanitize(deleted);
+    }
+
+    @PutMapping(path = "/{user-enc-id}/create",  produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator")
+    public UserRO createUser(@PathVariable("user-enc-id") String userEncId,
+                             @RequestBody UserRO user) {
+
+        Long userId = decryptEntityId(userEncId);
+        LOG.info("createUserData adminId: [{}], managedUserId: [{}]", userId);
+        // Update the user and mark the password as changed at this very instant of time
+        return uiUserService.adminCreateUserData(user);
+    }
+
+
+
     @PutMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
     @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN})
     public void updateUserList(@RequestBody UserRO[] updateEntities) {
-- 
GitLab