feat: policies on aggregates (#799)

* feat: move pw policy

* feat: default pw complexity policy

* fix: org password complexity policy

* fix: org password complexity policy

* fix: pw complexity policy with setup

* fix: age and lockout policies on aggregates

* fix: migration

* fix: org iam policy

* fix: org iam policy

* fix: org iam policy

* fix: tests

* fix: policy request

* fix: merge master

* fix(console): policies frontend (#817)

* fix policy build

* fix: age, complexity, lockout policies

* fix: ready return err of setup not done

* fix: fix remove policies in spoolers

* fix: fix remove policies in spoolers

* feat(console): policy settings for iam and org (#824)

* fix policy build

* fix: age, complexity, lockout policies

* fix pwd complexity

* policy remove action

* add imports

* fix accounts card, enable mgmt login policy

* lint

* add iam policy to admin

* toasts, i18n, show default

* routing, i18n

* reset policy, toast i18n, cleanup, routing

* policy delete permission

* lint style

* delete iam policy

* delete non project from grid list, i18n

* lint ts, style

* fix: remove instead delete

* feat(console): delete external idp from user (#835)

* dialog i18n, delete column and function

* dialog i18n

* fix rm button

* Update console/src/assets/i18n/de.json

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* Update console/src/assets/i18n/de.json

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* fix: revert env, rename policy, remove comments

* fix: lowercase sich

* fix: pr requests

* Update internal/iam/repository/eventsourcing/eventstore_test.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix: tests

* fix: tests

* fix(console): policies (#839)

* fix: nil pointer on get userdata (#815)

* fix: external login (#818)

* fix: external login

* fix: external login

* feat(console): delete user (#819)

* add action col to user table, i18n

* delete user from detail component

* lint

* fix(console): cleanup user detail and member components, user/me redirect, permission guards, filter, org policy guard, user table, scss cleanup (#808)

* fix: remove user.write guard for filtering

* border color

* fix user routing from member tables

* idp detail layout

* generic contact component

* fix redirect to auth user, user grant disable

* disable policy action without permission, i18n

* user-create flex fix, contact ng-content

* rm unused styles

* sidenav divider

* lint

* chore(deps-dev): bump @angular/cli from 10.1.3 to 10.1.4 in /console (#806)

* fix: user session with external login (#797)

* fix: user session with external login

* fix: tests

* fix: tests

* fix: change idp config name

* fix(container): stop copying / and instead only copy zitadel (#691)

* chore: stop copying / and instead only copy zitadel

* Update Dockerfile

* Update release.yml

* enable anchors debug

* fix(container): don't copy alpine content into scratch execpt pwd

* chore: remove need step

* merge master

* chore(deps-dev): bump @angular/cli from 10.1.3 to 10.1.4 in /console

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 10.1.3 to 10.1.4.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v10.1.3...v10.1.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular/language-service from 10.1.3 to 10.1.4 in /console (#805)

* fix: user session with external login (#797)

* fix: user session with external login

* fix: tests

* fix: tests

* fix: change idp config name

* fix(container): stop copying / and instead only copy zitadel (#691)

* chore: stop copying / and instead only copy zitadel

* Update Dockerfile

* Update release.yml

* enable anchors debug

* fix(container): don't copy alpine content into scratch execpt pwd

* chore: remove need step

* merge master

* chore(deps-dev): bump @angular/language-service in /console

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 10.1.3 to 10.1.4.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/10.1.4/packages/language-service)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump codelyzer from 6.0.0 to 6.0.1 in /console (#804)

* fix: user session with external login (#797)

* fix: user session with external login

* fix: tests

* fix: tests

* fix: change idp config name

* fix(container): stop copying / and instead only copy zitadel (#691)

* chore: stop copying / and instead only copy zitadel

* Update Dockerfile

* Update release.yml

* enable anchors debug

* fix(container): don't copy alpine content into scratch execpt pwd

* chore: remove need step

* merge master

* chore(deps-dev): bump codelyzer from 6.0.0 to 6.0.1 in /console

Bumps [codelyzer](https://github.com/mgechev/codelyzer) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/mgechev/codelyzer/releases)
- [Changelog](https://github.com/mgechev/codelyzer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mgechev/codelyzer/commits/6.0.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular from 0.1000.8 to 0.1001.4 in /console (#803)

* fix: user session with external login (#797)

* fix: user session with external login

* fix: tests

* fix: tests

* fix: change idp config name

* fix(container): stop copying / and instead only copy zitadel (#691)

* chore: stop copying / and instead only copy zitadel

* Update Dockerfile

* Update release.yml

* enable anchors debug

* fix(container): don't copy alpine content into scratch execpt pwd

* chore: remove need step

* merge master

* chore(deps-dev): bump @angular-devkit/build-angular in /console

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1000.8 to 0.1001.4.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <max@caos.ch>

* chore(deps): bump uuid from 8.3.0 to 8.3.1 in /console (#802)

* fix: user session with external login (#797)

* fix: user session with external login

* fix: tests

* fix: tests

* fix: change idp config name

* fix(container): stop copying / and instead only copy zitadel (#691)

* chore: stop copying / and instead only copy zitadel

* Update Dockerfile

* Update release.yml

* enable anchors debug

* fix(container): don't copy alpine content into scratch execpt pwd

* chore: remove need step

* merge master

* chore(deps): bump uuid from 8.3.0 to 8.3.1 in /console

Bumps [uuid](https://github.com/uuidjs/uuid) from 8.3.0 to 8.3.1.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v8.3.0...v8.3.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* create memberstable as common component

* iam member cleanup

* iam + org m table, user table service user avatar

* toast config

* fix selection emitter

* fix project grant table width

* project grant members refactor

* theme optimizations

* member table col delete

* lint

* fix table row color

* refactor grey color

* lint scss

* org list redirect on click, fix user table undef

* refresh table after grant add

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>

* fix(console): intercept navigator.language, set browser lang as default for user without explicit setting, user table outline, member create dialog import (#820)

* i18n interceptor, set language to browser lang

* nullcheck

* rm external idp log

* fix module imports, rm user displayname from i18n

* Update console/src/assets/i18n/de.json

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* fix: delete external idps from users (#822)

* fix(console): permission regex, account switcher null check, restrict app and member create access (#821)

* fix member table disable, gerneal regexp

* fix user session card, app disable

* memberships max count

* fix policy permissions

* permission check for member add dialog

* lint

* rm accounts log

* rm id regex

* fix: handle usermemberships on project and project grant delete (#825)

* fix: go handler

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>

* fix: tests

* fix: not needed error handling

Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Silvan <silvan.reusser@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@caos.ch>
This commit is contained in:
Fabi
2020-10-15 10:27:13 +02:00
committed by GitHub
parent adb24a52fc
commit fbb30840f1
248 changed files with 23960 additions and 13843 deletions

View File

@@ -42,6 +42,8 @@
flex-direction: column;
width: 100%;
padding: .5rem 0;
max-height: 310px;
overflow-y: auto;
border-top: 1px solid rgba(#8795a1, .3);
border-bottom: 1px solid rgba(#8795a1, .3);

View File

@@ -40,7 +40,8 @@
margin-bottom: 2rem;
h1 {
font-size: 1.2rem;
font-size: 1.5rem;
margin-top: 10px;
}
.desc {

View File

@@ -16,8 +16,7 @@
*ngIf="selection.hasValue() && serviceType!=PolicyComponentServiceType.MGMT" [disabled]="disabled">
<i class="las la-trash"></i>
</button>
<a [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled"
*ngIf="serviceType!=PolicyComponentServiceType.MGMT">
<a [routerLink]="createRouterLink" color="primary" mat-raised-button [disabled]="disabled">
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
</a>
</ng-template>

View File

@@ -1,62 +1,64 @@
<app-detail-layout [backRouterLink]="backroutes" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
[description]="(serviceType==PolicyComponentServiceType.MGMT ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEMGMT' : PolicyComponentServiceType.ADMIN ? 'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATEADMIN' : '') | translate">
<!--<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
<ng-template appHasRole
[appHasRole]="[serviceType === PolicyComponentServiceType.ADMIN ? 'iam.policy.delete' : 'org.policy.delete']">
<button matTooltip="{{'ORG.POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()"
mat-stroked-button>
{{'ORG.POLICY.DELETE' | translate}}
{{'ORG.POLICY.RESET' | translate}}
</button>
</ng-container>-->
</ng-template>
<div class="content" *ngIf="loginData">
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWUSERNAMEPASSWORD' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
[(ngModel)]="loginData.allowUsernamePassword" [disabled]="serviceType==PolicyComponentServiceType.MGMT">
[(ngModel)]="loginData.allowUsernamePassword">
</mat-slide-toggle>
</div>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWREGISTER' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="loginData.allowRegister"
[disabled]="serviceType==PolicyComponentServiceType.MGMT">
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="loginData.allowRegister">
</mat-slide-toggle>
</div>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.ALLOWEXTERNALIDP' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
[disabled]="serviceType==PolicyComponentServiceType.MGMT" [(ngModel)]="loginData.allowExternalIdp">
[(ngModel)]="loginData.allowExternalIdp">
</mat-slide-toggle>
</div>
</div>
<p class="subheader">{{'LOGINPOLICY.IDPS' | translate}}</p>
<h3 class="subheader">{{'LOGINPOLICY.IDPS' | translate}}</h3>
<div class="idps">
<div class="idp" *ngFor="let idp of idps">
<mat-icon *ngIf="serviceType!=PolicyComponentServiceType.MGMT" (click)="removeIdp(idp)" class="rm">
<mat-icon (click)="removeIdp(idp)" class="rm">
remove_circle</mat-icon>
<span>{{idp.name}}</span>
<span class="meta">{{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }}</span>
<span class="meta">{{ 'IDP.ID' | translate }}: {{idp.idpConfigId}}</span>
</div>
<div *ngIf="serviceType!=PolicyComponentServiceType.MGMT" class="new-idp" (click)="openDialog()">
<div class="new-idp" (click)="openDialog()">
<mat-icon>add</mat-icon>
</div>
</div>
<div class="btn-container">
<button (click)="savePolicy()" color="primary" type="submit"
[disabled]="serviceType==PolicyComponentServiceType.MGMT"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>
<ng-template appHasRole [appHasRole]="['org.idp.read']">
<app-card title="{{ 'IDP.LIST.TITLE' | translate }}" description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
<app-card class="idp-table-card" title="{{ 'IDP.LIST.TITLE' | translate }}"
description="{{ 'IDP.LIST.DESCRIPTION' | translate }}">
<app-idp-table [service]="service" [serviceType]="serviceType"
[disabled]="(['iam.idp.write$'] | hasRole | async) == false">
[disabled]="([serviceType == PolicyComponentServiceType.ADMIN ? 'iam.idp.write' : serviceType == PolicyComponentServiceType.MGMT ? 'org.idp.write' : ''] | hasRole | async) == false">
</app-idp-table>
</app-card>
</ng-template>

View File

@@ -1,3 +1,8 @@
.default {
color: #5282c1;
margin-top: 0;
}
.content {
padding-top: 1rem;
display: flex;
@@ -7,21 +12,15 @@
.row {
display: flex;
align-items: center;
padding: .5rem 0;
padding: .3rem 0;
.left-desc {
color: var(--grey);
font-size: .9rem;
}
.fill-space {
flex: 1;
}
.length-wrapper {
display: flex;
align-items: center;
}
}
}
@@ -37,6 +36,10 @@
}
}
.idp-table-card {
width: 100%;
}
.subheader {
width: 100%;
}

View File

@@ -1,7 +1,6 @@
import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {
@@ -39,7 +38,6 @@ export class LoginPolicyComponent implements OnDestroy {
public idps: MgmtIdpProviderView.AsObject[] | AdminIdpProviderView.AsObject[] = [];
constructor(
private route: ActivatedRoute,
private router: Router,
private toast: ToastService,
private dialog: MatDialog,
private injector: Injector,
@@ -107,7 +105,11 @@ export class LoginPolicyComponent implements OnDestroy {
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
mgmtreq.setAllowRegister(this.loginData.allowRegister);
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
return (this.service as ManagementService).UpdateLoginPolicy(mgmtreq);
if ((this.loginData as LoginPolicyView.AsObject).pb_default) {
return (this.service as ManagementService).CreateLoginPolicy(mgmtreq);
} else {
return (this.service as ManagementService).UpdateLoginPolicy(mgmtreq);
}
case PolicyComponentServiceType.ADMIN:
const adminreq = new DefaultLoginPolicy();
adminreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
@@ -119,25 +121,22 @@ export class LoginPolicyComponent implements OnDestroy {
public savePolicy(): void {
this.updateData().then(() => {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.router.navigate(['org']);
break;
case PolicyComponentServiceType.ADMIN:
this.router.navigate(['iam']);
break;
}
this.toast.showInfo('ORG.POLICY.LOGIN_POLICY.SAVED', true);
}).catch(error => {
this.toast.showError(error);
});
}
public deletePolicy(): Promise<Empty> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).RemoveLoginPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultLoginPolicy();
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).RemoveLoginPolicy().then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
@@ -179,15 +178,11 @@ export class LoginPolicyComponent implements OnDestroy {
}
}
public get backroutes(): string[] {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return ['/org'];
case PolicyComponentServiceType.ADMIN:
return ['/iam'];
break;
public get isDefault(): boolean {
if (this.loginData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.loginData as LoginPolicyView.AsObject).pb_default;
} else {
return false;
}
return [];
}
}

View File

@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { OrgIamPolicyComponent } from './org-iam-policy.component';
const routes: Routes = [
{
path: '',
component: OrgIamPolicyComponent,
data: {
animation: 'DetailPage',
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class OrgIamPolicyRoutingModule { }

View File

@@ -0,0 +1,27 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'ORG.POLICY.IAM_POLICY.TITLECREATE' | translate"
[description]="'ORG.POLICY.IAM_POLICY.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'ORG.POLICY.DEFAULTLABEL' | translate}}</p>
<ng-template appHasRole [appHasRole]="['iam.policy.delete']">
<button *ngIf="serviceType === PolicyComponentServiceType.MGMT" matTooltip="{{'ORG.POLICY.RESET' | translate}}"
color="warn" (click)="removePolicy()" mat-stroked-button>
{{'ORG.POLICY.RESET' | translate}}
</button>
</ng-template>
<div class="content" *ngIf="iamData">
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
[(ngModel)]="iamData.userLoginMustBeDomain">
</mat-slide-toggle>
</div>
</div>
<div class="btn-container">
<button (click)="savePolicy()" color="primary" type="submit"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>
</app-detail-layout>

View File

@@ -1,3 +1,8 @@
.default {
color: #5282c1;
margin-top: 0;
}
.content {
padding-top: 1rem;
display: flex;
@@ -7,10 +12,9 @@
.row {
display: flex;
align-items: center;
padding: .5rem 0;
padding: .3rem 0;
.left-desc {
color: var(--grey);
font-size: .9rem;
}

View File

@@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PasswordIamPolicyComponent } from './password-iam-policy.component';
import { OrgIamPolicyComponent } from './org-iam-policy.component';
describe('PasswordIamPolicyComponent', () => {
let component: PasswordIamPolicyComponent;
let fixture: ComponentFixture<PasswordIamPolicyComponent>;
describe('OrgIamPolicyComponent', () => {
let component: OrgIamPolicyComponent;
let fixture: ComponentFixture<OrgIamPolicyComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PasswordIamPolicyComponent],
declarations: [OrgIamPolicyComponent],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PasswordIamPolicyComponent);
fixture = TestBed.createComponent(OrgIamPolicyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@@ -0,0 +1,132 @@
import { Component, Injector, Input, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { OrgIamPolicyView as AdminOrgIamPolicyView } from 'src/app/proto/generated/admin_pb';
import { Org } from 'src/app/proto/generated/auth_pb';
import { OrgIamPolicyView as MgmtOrgIamPolicyView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { StorageService } from 'src/app/services/storage.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
selector: 'app-org-iam-policy',
templateUrl: './org-iam-policy.component.html',
styleUrls: ['./org-iam-policy.component.scss'],
})
export class OrgIamPolicyComponent implements OnDestroy {
@Input() service!: AdminService;
private managementService!: ManagementService;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public iamData!: AdminOrgIamPolicyView.AsObject | MgmtOrgIamPolicyView.AsObject;
private sub: Subscription = new Subscription();
private org!: Org.AsObject;
public PolicyComponentServiceType: any = PolicyComponentServiceType;
constructor(
private route: ActivatedRoute,
private toast: ToastService,
private sessionStorage: StorageService,
private injector: Injector,
private adminService: AdminService,
) {
const temporg = this.sessionStorage.getItem('organization') as Org.AsObject;
if (temporg) {
this.org = temporg;
}
this.sub = this.route.data.pipe(switchMap(data => {
this.serviceType = data.serviceType;
if (this.serviceType === PolicyComponentServiceType.MGMT) {
this.managementService = this.injector.get(ManagementService as Type<ManagementService>);
}
return this.route.params;
})).subscribe(_ => {
this.getData().then(data => {
if (data) {
this.iamData = data.toObject();
}
});
});
}
public ngOnDestroy(): void {
this.sub.unsubscribe();
}
private async getData(): Promise<AdminOrgIamPolicyView | MgmtOrgIamPolicyView | undefined> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return this.managementService.GetMyOrgIamPolicy();
case PolicyComponentServiceType.ADMIN:
if (this.org?.id) {
return this.adminService.GetOrgIamPolicy(this.org.id);
}
break;
}
}
public savePolicy(): void {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.iamData as MgmtOrgIamPolicyView.AsObject).pb_default) {
this.adminService.CreateOrgIamPolicy(
this.org.id,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
break;
} else {
this.adminService.UpdateOrgIamPolicy(
this.org.id,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
break;
}
case PolicyComponentServiceType.ADMIN:
// update Default org iam policy?
this.adminService.UpdateOrgIamPolicy(
this.org.id,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
break;
}
}
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
this.adminService.RemoveOrgIamPolicy(this.org.id).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
public get isDefault(): boolean {
if (this.iamData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.iamData as MgmtOrgIamPolicyView.AsObject).pb_default;
} else {
return false;
}
}
}

View File

@@ -11,13 +11,13 @@ import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
import { PasswordIamPolicyRoutingModule } from './password-iam-policy-routing.module';
import { PasswordIamPolicyComponent } from './password-iam-policy.component';
import { OrgIamPolicyRoutingModule } from './org-iam-policy-routing.module';
import { OrgIamPolicyComponent } from './org-iam-policy.component';
@NgModule({
declarations: [PasswordIamPolicyComponent],
declarations: [OrgIamPolicyComponent],
imports: [
PasswordIamPolicyRoutingModule,
OrgIamPolicyRoutingModule,
CommonModule,
FormsModule,
MatInputModule,
@@ -31,4 +31,4 @@ import { PasswordIamPolicyComponent } from './password-iam-policy.component';
DetailLayoutModule,
],
})
export class PasswordIamPolicyModule { }
export class OrgIamPolicyModule { }

View File

@@ -1,7 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PasswordAgePolicyComponent } from './password-age-policy.component';
const routes: Routes = [
@@ -10,15 +9,6 @@ const routes: Routes = [
component: PasswordAgePolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.MODIFY,
},
},
{
path: 'create',
component: PasswordAgePolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.CREATE,
},
},
];

View File

@@ -1,17 +1,14 @@
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
[description]="desc ? (desc | translate) : ''">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'ORG.POLICY.PWD_AGE.TITLE' | translate" [description]="'ORG.POLICY.PWD_AGE.DESCRIPTION' | translate">
<ng-template appHasRole
[appHasRole]="[serviceType === PolicyComponentServiceType.ADMIN ? 'iam.policy.delete' : 'org.policy.delete']">
<button matTooltip="{{'ORG.POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()"
mat-stroked-button>
{{'ORG.POLICY.DELETE' | translate}}
{{'ORG.POLICY.RESET' | translate}}
</button>
</ng-template>
<div class="content" *ngIf="ageData">
<mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="ageData.description" required />
</mat-form-field>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.EXPIREWARNDAYS' | translate}}</span>
<span class="fill-space"></span>

View File

@@ -7,7 +7,7 @@
.row {
display: flex;
align-items: center;
padding: .5rem 0;
padding: .3rem 0;
.left-desc {
color: var(--grey);
@@ -21,6 +21,7 @@
.length-wrapper {
display: flex;
align-items: center;
margin-right: -.6rem;
}
}
}

View File

@@ -1,17 +1,14 @@
import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {
OrgIamPolicy,
PasswordAgePolicy,
PasswordComplexityPolicy,
PasswordLockoutPolicy,
} from 'src/app/proto/generated/management_pb';
import { DefaultPasswordAgePolicyView } from 'src/app/proto/generated/admin_pb';
import { PasswordAgePolicyView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
@@ -20,37 +17,37 @@ import { PolicyComponentAction } from '../policy-component-action.enum';
styleUrls: ['./password-age-policy.component.scss'],
})
export class PasswordAgePolicyComponent implements OnDestroy {
public title: string = '';
public desc: string = '';
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public service!: AdminService | ManagementService;
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
public PolicyComponentAction: any = PolicyComponentAction;
public ageData!: PasswordAgePolicy.AsObject;
public ageData!: PasswordAgePolicyView.AsObject | DefaultPasswordAgePolicyView.AsObject;
private sub: Subscription = new Subscription();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
constructor(
private route: ActivatedRoute,
private mgmtService: ManagementService,
private router: Router,
private toast: ToastService,
private injector: Injector,
) {
this.sub = this.route.data.pipe(switchMap(data => {
this.componentAction = data.action;
return this.route.params;
})).subscribe(params => {
this.title = 'ORG.POLICY.PWD_AGE.TITLECREATE';
this.desc = 'ORG.POLICY.PWD_AGE.DESCRIPTIONCREATE';
if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => {
if (data) {
this.ageData = data.toObject() as PasswordAgePolicy.AsObject;
}
});
this.serviceType = data.serviceType;
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
}
return this.route.params;
})).subscribe(() => {
this.getData().then(data => {
if (data) {
this.ageData = data.toObject();
}
});
});
}
@@ -58,19 +55,28 @@ export class PasswordAgePolicyComponent implements OnDestroy {
this.sub.unsubscribe();
}
private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
this.title = 'ORG.POLICY.PWD_AGE.TITLE';
this.desc = 'ORG.POLICY.PWD_AGE.DESCRIPTION';
return this.mgmtService.GetPasswordAgePolicy();
private async getData():
Promise<PasswordAgePolicyView | DefaultPasswordAgePolicyView> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordAgePolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordAgePolicy();
}
}
public deletePolicy(): void {
this.mgmtService.DeletePasswordAgePolicy(this.ageData.id).then(() => {
this.toast.showInfo('Successfully deleted');
}).catch(error => {
this.toast.showError(error);
});
public removePolicy(): void {
if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).RemovePasswordAgePolicy().then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
public incrementExpireWarnDays(): void {
@@ -98,29 +104,33 @@ export class PasswordAgePolicyComponent implements OnDestroy {
}
public savePolicy(): void {
if (this.componentAction === PolicyComponentAction.CREATE) {
this.mgmtService.CreatePasswordAgePolicy(
this.ageData.description,
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
this.mgmtService.UpdatePasswordAgePolicy(
this.ageData.description,
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.ageData as PasswordAgePolicyView.AsObject).pb_default) {
(this.service as ManagementService).CreatePasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).catch(error => {
this.toast.showError(error);
});
} else {
(this.service as ManagementService).UpdatePasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).catch(error => {
this.toast.showError(error);
});
}
break;
case PolicyComponentServiceType.ADMIN:
(this.service as AdminService).UpdateDefaultPasswordAgePolicy(
this.ageData.maxAgeDays,
this.ageData.expireWarnDays,
).catch(error => {
this.toast.showError(error);
});
break;
}
}
}

View File

@@ -1,7 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
const routes: Routes = [
@@ -10,15 +9,6 @@ const routes: Routes = [
component: PasswordComplexityPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.MODIFY,
},
},
{
path: 'create',
component: PasswordComplexityPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.CREATE,
},
},
];

View File

@@ -1,17 +1,17 @@
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
[description]="desc ? (desc | translate) : ''">
<ng-template appHasRole [appHasRole]="['policy.write$']">
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'ORG.POLICY.PWD_COMPLEXITY.TITLE' | translate"
[description]="'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'ORG.POLICY.DEFAULTLABEL' | translate}}</p>
<ng-template appHasRole
[appHasRole]="[serviceType === PolicyComponentServiceType.ADMIN ? 'iam.policy.delete' : 'org.policy.delete']">
<button matTooltip="{{'ORG.POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()"
mat-stroked-button>
{{'ORG.POLICY.DELETE' | translate}}
{{'ORG.POLICY.RESET' | translate}}
</button>
</ng-template>
<div *ngIf="complexityData" class="content">
<mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="complexityData.description" required />
</mat-form-field>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.MINLENGTH' | translate}}</span>
<span class="fill-space"></span>
@@ -54,7 +54,7 @@
</div>
<div class="btn-container">
<button (click)="savePolicy()" color="primary" type="submit" [disabled]="!complexityData?.description"
<button (click)="savePolicy()" color="primary" type="submit"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>
</app-detail-layout>

View File

@@ -1,3 +1,8 @@
.default {
color: #5282c1;
margin-top: 0;
}
.content {
padding-top: 1rem;
display: flex;
@@ -7,10 +12,9 @@
.row {
display: flex;
align-items: center;
padding: .5rem 0;
padding: .3rem 0;
.left-desc {
color: var(--grey);
font-size: .9rem;
}
@@ -21,6 +25,7 @@
.length-wrapper {
display: flex;
align-items: center;
margin-right: -.6rem;
}
}
}

View File

@@ -1,17 +1,14 @@
import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {
OrgIamPolicy,
PasswordAgePolicy,
PasswordComplexityPolicy,
PasswordLockoutPolicy,
} from 'src/app/proto/generated/management_pb';
import { DefaultPasswordComplexityPolicy } from 'src/app/proto/generated/admin_pb';
import { PasswordComplexityPolicyView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
selector: 'app-password-policy',
@@ -19,37 +16,37 @@ import { PolicyComponentAction } from '../policy-component-action.enum';
styleUrls: ['./password-complexity-policy.component.scss'],
})
export class PasswordComplexityPolicyComponent implements OnDestroy {
public title: string = '';
public desc: string = '';
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
public service!: ManagementService | AdminService;
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
public PolicyComponentAction: any = PolicyComponentAction;
public complexityData!: PasswordComplexityPolicy.AsObject;
public complexityData!: PasswordComplexityPolicyView.AsObject | DefaultPasswordComplexityPolicy.AsObject;
private sub: Subscription = new Subscription();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
constructor(
private route: ActivatedRoute,
private mgmtService: ManagementService,
private router: Router,
private toast: ToastService,
private injector: Injector,
) {
this.sub = this.route.data.pipe(switchMap(data => {
this.componentAction = data.action;
return this.route.params;
})).subscribe(params => {
this.title = 'ORG.POLICY.PWD_COMPLEXITY.TITLECREATE';
this.desc = 'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTIONCREATE';
this.serviceType = data.serviceType;
if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => {
if (data) {
this.complexityData = data.toObject() as PasswordComplexityPolicy.AsObject;
}
});
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
}
return this.route.params;
})).subscribe(() => {
this.getData().then(data => {
if (data) {
this.complexityData = data.toObject();
}
});
});
}
@@ -57,19 +54,27 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
this.sub.unsubscribe();
}
private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
this.title = 'ORG.POLICY.PWD_COMPLEXITY.TITLE';
this.desc = 'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTION';
return this.mgmtService.GetPasswordComplexityPolicy();
private async getData():
Promise<PasswordComplexityPolicyView | DefaultPasswordComplexityPolicy> {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordComplexityPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordComplexityPolicy();
}
}
public deletePolicy(): void {
this.mgmtService.DeletePasswordComplexityPolicy(this.complexityData.id).then(() => {
this.toast.showInfo('Successfully deleted');
}).catch(error => {
this.toast.showError(error);
});
public removePolicy(): void {
if (this.service instanceof ManagementService) {
this.service.removePasswordComplexityPolicy().then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
public incrementLength(): void {
@@ -85,35 +90,56 @@ export class PasswordComplexityPolicyComponent implements OnDestroy {
}
public savePolicy(): void {
if (this.componentAction === PolicyComponentAction.CREATE) {
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.complexityData as PasswordComplexityPolicyView.AsObject).pb_default) {
(this.service as ManagementService).CreatePasswordComplexityPolicy(
this.mgmtService.CreatePasswordComplexityPolicy(
this.complexityData.description,
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
this.complexityData.hasSymbol,
this.complexityData.minLength,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
this.complexityData.hasSymbol,
this.complexityData.minLength,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
} else {
(this.service as ManagementService).UpdatePasswordComplexityPolicy(
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
this.complexityData.hasSymbol,
this.complexityData.minLength,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
}
break;
case PolicyComponentServiceType.ADMIN:
(this.service as AdminService).UpdateDefaultPasswordComplexityPolicy(
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
this.complexityData.hasSymbol,
this.complexityData.minLength,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
break;
}
}
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
this.mgmtService.UpdatePasswordComplexityPolicy(
this.complexityData.description,
this.complexityData.hasLowercase,
this.complexityData.hasUppercase,
this.complexityData.hasNumber,
this.complexityData.hasSymbol,
this.complexityData.minLength,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
public get isDefault(): boolean {
if (this.complexityData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.complexityData as PasswordComplexityPolicyView.AsObject).pb_default;
} else {
return false;
}
}
}

View File

@@ -1,30 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PasswordIamPolicyComponent } from './password-iam-policy.component';
const routes: Routes = [
{
path: '',
component: PasswordIamPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.MODIFY,
},
},
{
path: 'create',
component: PasswordIamPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.CREATE,
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PasswordIamPolicyRoutingModule { }

View File

@@ -1,28 +0,0 @@
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
[description]="desc ? (desc | translate) : ''">
<!-- <ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
mat-stroked-button>
{{'ORG.POLICY.DELETE' | translate}}
</button>
</ng-template> -->
<div class="content" *ngIf="iamData">
<mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="iamData.description" required />
</mat-form-field>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl
[(ngModel)]="iamData.userLoginMustBeDomain">
</mat-slide-toggle>
</div>
</div>
<div class="btn-container">
<button (click)="savePolicy()" color="primary" type="submit" [disabled]="!iamData?.description"
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
</div>
</app-detail-layout>

View File

@@ -1,102 +0,0 @@
import { Component, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {
OrgIamPolicy,
PasswordAgePolicy,
PasswordComplexityPolicy,
PasswordLockoutPolicy,
} from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { StorageService } from 'src/app/services/storage.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentAction } from '../policy-component-action.enum';
@Component({
selector: 'app-password-iam-policy',
templateUrl: './password-iam-policy.component.html',
styleUrls: ['./password-iam-policy.component.scss'],
})
export class PasswordIamPolicyComponent implements OnDestroy {
public title: string = '';
public desc: string = '';
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
public PolicyComponentAction: any = PolicyComponentAction;
public iamData!: OrgIamPolicy.AsObject;
private sub: Subscription = new Subscription();
constructor(
private route: ActivatedRoute,
private mgmtService: ManagementService,
private adminService: AdminService,
private router: Router,
private toast: ToastService,
private sessionStorage: StorageService,
) {
this.sub = this.route.data.pipe(switchMap(data => {
this.componentAction = data.action;
console.log(data.action);
return this.route.params;
})).subscribe(params => {
this.title = 'ORG.POLICY.IAM_POLICY.TITLECREATE';
this.desc = 'ORG.POLICY.IAM_POLICY.DESCRIPTIONCREATE';
if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => {
if (data) {
this.iamData = data.toObject() as OrgIamPolicy.AsObject;
}
});
}
});
}
public ngOnDestroy(): void {
this.sub.unsubscribe();
}
private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
this.title = 'ORG.POLICY.IAM_POLICY.TITLECREATE';
this.desc = 'ORG.POLICY.IAM_POLICY.DESCRIPTIONCREATE';
return this.mgmtService.GetMyOrgIamPolicy();
}
public savePolicy(): void {
if (this.componentAction === PolicyComponentAction.CREATE) {
const orgId = this.sessionStorage.getItem('organization');
if (orgId) {
this.adminService.CreateOrgIamPolicy(
orgId,
this.iamData.description,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
}
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
const orgId = this.sessionStorage.getItem('organization');
if (orgId) {
this.adminService.UpdateOrgIamPolicy(
orgId,
this.iamData.description,
this.iamData.userLoginMustBeDomain,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
}
}
}
}

View File

@@ -1,7 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component';
const routes: Routes = [
@@ -10,15 +9,6 @@ const routes: Routes = [
component: PasswordLockoutPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.MODIFY,
},
},
{
path: 'create',
component: PasswordLockoutPolicyComponent,
data: {
animation: 'DetailPage',
action: PolicyComponentAction.CREATE,
},
},
];

View File

@@ -1,17 +1,16 @@
<app-detail-layout [backRouterLink]="[ '/org']" [title]="title ? (title | translate) : ''"
[description]="desc ? (desc | translate) : ''">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'ORG.POLICY.PWD_LOCKOUT.TITLE' | translate"
[description]="'ORG.POLICY.PWD_LOCKOUT.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'ORG.POLICY.DEFAULTLABEL' | translate}}</p>
<ng-template appHasRole
[appHasRole]="[serviceType === PolicyComponentServiceType.ADMIN ? 'iam.policy.delete' : 'org.policy.delete']">
<button matTooltip="{{'ORG.POLICY.RESET' | translate}}" color="warn" (click)="removePolicy()"
mat-stroked-button>
{{'ORG.POLICY.DELETE' | translate}}
{{'ORG.POLICY.RESET' | translate}}
</button>
</ng-template>
<div class="content" *ngIf="lockoutData">
<mat-form-field class="description-formfield" appearance="outline">
<mat-label>{{ 'ORG.POLICY.DATA.DESCRIPTION' | translate }}</mat-label>
<input matInput name="description" ngDefaultControl [(ngModel)]="lockoutData.description" required />
</mat-form-field>
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.MAXATTEMPTS' | translate}}</span>
<span class="fill-space"></span>
@@ -28,8 +27,8 @@
<div class="row">
<span class="left-desc">{{'ORG.POLICY.DATA.SHOWLOCKOUTFAILURES' | translate}}</span>
<span class="fill-space"></span>
<mat-slide-toggle color="primary" name="showLockOutFailures" ngDefaultControl
[(ngModel)]="lockoutData.showLockOutFailures">
<mat-slide-toggle color="primary" name="showLockoutFailure" ngDefaultControl
[(ngModel)]="lockoutData.showLockoutFailure">
</mat-slide-toggle>
</div>
</div>

View File

@@ -1,3 +1,7 @@
.default {
color: #5282c1;
margin-top: 0;
}
.content {
padding-top: 1rem;
@@ -8,10 +12,9 @@
.row {
display: flex;
align-items: center;
padding: .5rem 0;
padding: .3rem 0;
.left-desc {
color: var(--grey);
font-size: .9rem;
}

View File

@@ -1,18 +1,15 @@
import { Component, OnDestroy } from '@angular/core';
import { Component, Injector, Input, OnDestroy, Type } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {
OrgIamPolicy,
PasswordAgePolicy,
PasswordComplexityPolicy,
PasswordLockoutPolicy,
} from 'src/app/proto/generated/management_pb';
import { DefaultPasswordLockoutPolicyView } from 'src/app/proto/generated/admin_pb';
import { PasswordLockoutPolicyView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
import { PolicyComponentAction } from '../policy-component-action.enum';
import { PolicyComponentServiceType } from '../policy-component-types.enum';
@Component({
selector: 'app-password-lockout-policy',
@@ -20,37 +17,39 @@ import { PolicyComponentAction } from '../policy-component-action.enum';
styleUrls: ['./password-lockout-policy.component.scss'],
})
export class PasswordLockoutPolicyComponent implements OnDestroy {
public title: string = '';
public desc: string = '';
@Input() public service!: ManagementService | AdminService;
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
public PolicyComponentAction: any = PolicyComponentAction;
public lockoutForm!: FormGroup;
public lockoutData!: PasswordLockoutPolicy.AsObject;
public lockoutData!: PasswordLockoutPolicyView.AsObject;
private sub: Subscription = new Subscription();
public PolicyComponentServiceType: any = PolicyComponentServiceType;
constructor(
private route: ActivatedRoute,
private mgmtService: ManagementService,
private router: Router,
private toast: ToastService,
private injector: Injector,
) {
this.sub = this.route.data.pipe(switchMap(data => {
this.componentAction = data.action;
return this.route.params;
})).subscribe(params => {
this.title = 'ORG.POLICY.PWD_LOCKOUT.TITLECREATE';
this.desc = 'ORG.POLICY.PWD_LOCKOUT.DESCRIPTIONCREATE';
this.serviceType = data.serviceType;
if (this.componentAction === PolicyComponentAction.MODIFY) {
this.getData(params).then(data => {
if (data) {
this.lockoutData = data.toObject() as PasswordLockoutPolicy.AsObject;
}
});
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
this.service = this.injector.get(ManagementService as Type<ManagementService>);
break;
case PolicyComponentServiceType.ADMIN:
this.service = this.injector.get(AdminService as Type<AdminService>);
break;
}
return this.route.params;
})).subscribe(() => {
this.getData().then(data => {
if (data) {
this.lockoutData = data.toObject() as PasswordLockoutPolicyView.AsObject;
}
});
});
}
@@ -58,20 +57,27 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
this.sub.unsubscribe();
}
private async getData(params: any):
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
private getData(): Promise<PasswordLockoutPolicyView | DefaultPasswordLockoutPolicyView> {
this.title = 'ORG.POLICY.PWD_LOCKOUT.TITLE';
this.desc = 'ORG.POLICY.PWD_LOCKOUT.DESCRIPTION';
return this.mgmtService.GetPasswordLockoutPolicy();
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
return (this.service as ManagementService).GetPasswordLockoutPolicy();
case PolicyComponentServiceType.ADMIN:
return (this.service as AdminService).GetDefaultPasswordLockoutPolicy();
}
}
public deletePolicy(): void {
this.mgmtService.DeletePasswordLockoutPolicy(this.lockoutData.id).then(() => {
this.toast.showInfo('Successfully deleted');
}).catch(error => {
this.toast.showError(error);
});
public removePolicy(): void {
if (this.service instanceof ManagementService) {
this.service.RemovePasswordLockoutPolicy().then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.RESETSUCCESS', true);
setTimeout(() => {
this.getData();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
}
public incrementMaxAttempts(): void {
@@ -87,27 +93,44 @@ export class PasswordLockoutPolicyComponent implements OnDestroy {
}
public savePolicy(): void {
if (this.componentAction === PolicyComponentAction.CREATE) {
this.mgmtService.CreatePasswordLockoutPolicy(
this.lockoutData.description,
let promise: Promise<any>;
if (this.service instanceof AdminService) {
promise = this.service.UpdateDefaultPasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockOutFailures,
this.lockoutData.showLockoutFailure,
).then(() => {
this.router.navigate(['org']);
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
} else {
if ((this.lockoutData as PasswordLockoutPolicyView.AsObject).pb_default) {
promise = this.service.CreatePasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockoutFailure,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
} else {
promise = this.service.UpdatePasswordLockoutPolicy(
this.lockoutData.maxAttempts,
this.lockoutData.showLockoutFailure,
).then(() => {
this.toast.showInfo('ORG.POLICY.TOAST.SET', true);
}).catch(error => {
this.toast.showError(error);
});
}
}
}
this.mgmtService.UpdatePasswordLockoutPolicy(
this.lockoutData.description,
this.lockoutData.maxAttempts,
this.lockoutData.showLockOutFailures,
).then(() => {
this.router.navigate(['org']);
}).catch(error => {
this.toast.showError(error);
});
public get isDefault(): boolean {
if (this.lockoutData && this.serviceType === PolicyComponentServiceType.MGMT) {
return (this.lockoutData as PasswordLockoutPolicyView.AsObject).pb_default;
} else {
return false;
}
}
}

View File

@@ -1,5 +0,0 @@
export enum PolicyComponentAction {
CREATE = 'create',
MODIFY = 'modify',
}

View File

@@ -3,6 +3,29 @@
<p class="top-desc">{{'IAM.POLICY.DESCRIPTION' | translate}}</p>
<div class="row-lyt">
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
<div class="p-item card">
<div class="avatar">
<mat-icon class="icon" svgIcon="mdi_textbox_password"></mat-icon>
</div>
<div class="title">
<span>{{'ORG.POLICY.PWD_COMPLEXITY.TITLE' | translate}}</span>
<button mat-icon-button disabled>
<i *ngIf="complexityPolicy" class="icon las la-check-circle"></i>
</button>
</div>
<p class="desc">
{{'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate}}</p>
<span class="fill-space"></span>
<div class="btn-wrapper">
<button [disabled]="!complexityPolicy" [routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]"
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
</div>
</div>
</ng-template>
<ng-template appHasRole [appHasRole]="['policy.read']">
<div class="p-item card">
<div class="avatar">
@@ -27,4 +50,29 @@
</div>
</div>
</ng-template>
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
<div class="p-item card">
<div class="avatar">
<i class="icon las la-gem"></i>
</div>
<div class="title">
<span>{{'ORG.POLICY.IAM_POLICY.TITLE' | translate}}</span>
<button mat-icon-button disabled>
<i *ngIf="iamPolicy" class="icon las la-check-circle"></i>
</button>
</div>
<p class="desc">
{{'ORG.POLICY.IAM_POLICY.DESCRIPTION' | translate}}</p>
<span class="fill-space"></span>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button [disabled]="!iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM ]"
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>
</div>
</ng-template>
</div>

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
import { DefaultLoginPolicy } from 'src/app/proto/generated/admin_pb';
import { DefaultLoginPolicy, DefaultPasswordComplexityPolicyView, OrgIamPolicyView } from 'src/app/proto/generated/admin_pb';
import { PolicyState } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
@@ -10,7 +10,9 @@ import { AdminService } from 'src/app/services/admin.service';
styleUrls: ['./iam-policy-grid.component.scss'],
})
export class IamPolicyGridComponent {
public complexityPolicy!: DefaultPasswordComplexityPolicyView.AsObject;
public loginPolicy!: DefaultLoginPolicy.AsObject;
public iamPolicy!: OrgIamPolicyView.AsObject;
public PolicyState: any = PolicyState;
public PolicyComponentType: any = PolicyComponentType;
@@ -23,5 +25,7 @@ export class IamPolicyGridComponent {
private getData(): void {
this.adminService.GetDefaultLoginPolicy().then(data => this.loginPolicy = data.toObject());
this.adminService.GetDefaultOrgIamPolicy().then(data => this.iamPolicy = data.toObject());
this.adminService.GetDefaultPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject());
}
}

View File

@@ -47,12 +47,49 @@ const routes: Routes = [
],
},
{
path: `policy/${PolicyComponentType.LOGIN}`,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/login-policy/login-policy.module')
.then(m => m.LoginPolicyModule),
path: 'policy',
children: [
{
path: PolicyComponentType.AGE,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/password-age-policy/password-age-policy.module')
.then(m => m.PasswordAgePolicyModule),
},
{
path: PolicyComponentType.LOCKOUT,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/password-lockout-policy/password-lockout-policy.module')
.then(m => m.PasswordLockoutPolicyModule),
},
{
path: PolicyComponentType.COMPLEXITY,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/password-complexity-policy/password-complexity-policy.module')
.then(m => m.PasswordComplexityPolicyModule),
},
{
path: PolicyComponentType.IAM,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/org-iam-policy/org-iam-policy.module')
.then(m => m.OrgIamPolicyModule),
},
{
path: PolicyComponentType.LOGIN,
data: {
serviceType: PolicyComponentServiceType.ADMIN,
},
loadChildren: () => import('src/app/modules/policies/login-policy/login-policy.module')
.then(m => m.LoginPolicyModule),
},
],
},
];

View File

@@ -7,7 +7,7 @@ import { Router } from '@angular/router';
import { take } from 'rxjs/operators';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from 'src/app/pages/validators';
import { CreateHumanRequest, CreateOrgRequest, Gender, OrgSetUpResponse } from 'src/app/proto/generated/admin_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/auth_pb';
import { PasswordComplexityPolicy as MgmtPasswordComplexityPolicy } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
import { ManagementService } from 'src/app/services/mgmt.service';
@@ -57,7 +57,7 @@ export class OrgCreateComponent {
public genders: Gender[] = [Gender.GENDER_FEMALE, Gender.GENDER_MALE, Gender.GENDER_UNSPECIFIED];
public languages: string[] = ['de', 'en'];
public policy!: PasswordComplexityPolicy.AsObject;
public policy!: MgmtPasswordComplexityPolicy.AsObject;
public usePassword: boolean = false;
public forSelf: boolean = true;

View File

@@ -43,23 +43,35 @@ const routes: Routes = [
children: [
{
path: PolicyComponentType.AGE,
data: {
serviceType: PolicyComponentServiceType.MGMT,
},
loadChildren: () => import('src/app/modules/policies/password-age-policy/password-age-policy.module')
.then(m => m.PasswordAgePolicyModule),
},
{
path: PolicyComponentType.LOCKOUT,
data: {
serviceType: PolicyComponentServiceType.MGMT,
},
loadChildren: () => import('src/app/modules/policies/password-lockout-policy/password-lockout-policy.module')
.then(m => m.PasswordLockoutPolicyModule),
},
{
path: PolicyComponentType.COMPLEXITY,
data: {
serviceType: PolicyComponentServiceType.MGMT,
},
loadChildren: () => import('src/app/modules/policies/password-complexity-policy/password-complexity-policy.module')
.then(m => m.PasswordComplexityPolicyModule),
},
{
path: PolicyComponentType.IAM,
loadChildren: () => import('src/app/modules/policies/password-iam-policy/password-iam-policy.module')
.then(m => m.PasswordIamPolicyModule),
data: {
serviceType: PolicyComponentServiceType.MGMT,
},
loadChildren: () => import('src/app/modules/policies/org-iam-policy/org-iam-policy.module')
.then(m => m.OrgIamPolicyModule),
},
{
path: PolicyComponentType.LOGIN,

View File

@@ -3,34 +3,28 @@
<p class="top-desc">{{'ORG.POLICY.DESCRIPTION' | translate}}</p>
<div class="row-lyt">
<div class="p-item card">
<div class="avatar">
<mat-icon class="icon" svgIcon="mdi_textbox_password"></mat-icon>
</div>
<div class="title">
<span>{{'ORG.POLICY.PWD_COMPLEXITY.TITLE' | translate}}</span>
<button mat-icon-button disabled>
<i *ngIf="complexityPolicy" class="icon las la-check-circle"></i>
</button>
</div>
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
<div class="p-item card">
<div class="avatar">
<mat-icon class="icon" svgIcon="mdi_textbox_password"></mat-icon>
</div>
<div class="title">
<span>{{'ORG.POLICY.PWD_COMPLEXITY.TITLE' | translate}}</span>
<button mat-icon-button disabled>
<i *ngIf="complexityPolicy" class="icon las la-check-circle"></i>
</button>
</div>
<p *ngIf="complexityPolicy?.description; else showDescComplexity" class="desc">
{{ complexityPolicy.description }}</p>
<ng-template #showDescComplexity>
<p class="desc">
{{'ORG.POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate}}</p>
</ng-template>
<span class="fill-space"></span>
<div class="btn-wrapper" *ngIf="(['policy.write'] | hasRole) as writePolicy$">
<button [disabled]="complexityPolicy || (writePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY,'create' ]" color="primary"
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
<button [disabled]="!complexityPolicy || (writePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]" mat-stroked-button
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
<span class="fill-space"></span>
<div class="btn-wrapper">
<button [disabled]="!complexityPolicy" [routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]"
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
</div>
</div>
</div>
</ng-template>
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
<div class="p-item card">
@@ -44,22 +38,15 @@
</button>
</div>
<p *ngIf="iamPolicy?.description; else showDescIAM" class="desc">
{{ iamPolicy.description }}</p>
<ng-template #showDescIAM>
<p class="desc">
{{'ORG.POLICY.IAM_POLICY.DESCRIPTION' | translate}}</p>
</ng-template>
<p class="desc">
{{'ORG.POLICY.IAM_POLICY.DESCRIPTION' | translate}}</p>
<span class="fill-space"></span>
<div class="btn-wrapper" *ngIf="(['iam.policy.write$'] | hasRole) as iamWritePolicy$">
<button [disabled]="iamPolicy || (iamWritePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.IAM,'create' ]" color="primary"
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
<button [disabled]="!iamPolicy || (iamWritePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.IAM ]" mat-stroked-button
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button [disabled]="!iamPolicy" [routerLink]="[ 'policy', PolicyComponentType.IAM ]"
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>
</div>
</ng-template>
@@ -82,13 +69,11 @@
</ng-template>
<span class="fill-space"></span>
<div class="btn-wrapper" *ngIf="(['policy.write'] | hasRole) as writePolicy$">
<button [disabled]="loginPolicy || (writePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.LOGIN,'create' ]" color="primary"
mat-raised-button>{{'ORG.POLICY.BTN_INSTALL' | translate}}</button>
<button [disabled]="!loginPolicy || (writePolicy$ | async) == false"
[routerLink]="[ 'policy', PolicyComponentType.LOGIN ]" mat-stroked-button
[matTooltip]="'ACTIONS.CONFIGURE' | translate">{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['policy.write']">
<button [disabled]="!loginPolicy" [routerLink]="[ 'policy', PolicyComponentType.LOGIN ]"
mat-stroked-button>{{'ORG.POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>
</div>
</ng-template>

View File

@@ -1,7 +1,13 @@
import { Component } from '@angular/core';
import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum';
import { LoginPolicy, OrgIamPolicy, PasswordComplexityPolicy, PolicyState } from 'src/app/proto/generated/management_pb';
import {
LoginPolicyView,
OrgIamPolicyView,
PasswordComplexityPolicyView,
PolicyState,
} from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'app-policy-grid',
@@ -9,21 +15,24 @@ import { ManagementService } from 'src/app/services/mgmt.service';
styleUrls: ['./policy-grid.component.scss'],
})
export class PolicyGridComponent {
public complexityPolicy!: PasswordComplexityPolicy.AsObject;
public iamPolicy!: OrgIamPolicy.AsObject;
public loginPolicy!: LoginPolicy.AsObject;
public complexityPolicy!: PasswordComplexityPolicyView.AsObject;
public iamPolicy!: OrgIamPolicyView.AsObject;
public loginPolicy!: LoginPolicyView.AsObject;
public PolicyState: any = PolicyState;
public PolicyComponentType: any = PolicyComponentType;
constructor(
private mgmtService: ManagementService,
public mgmtService: ManagementService,
private toast: ToastService,
) {
this.getData();
}
private getData(): void {
this.mgmtService.GetPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject());
this.mgmtService.GetPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject()).catch(error => {
this.toast.showError(error);
});
this.mgmtService.GetMyOrgIamPolicy().then(data => this.iamPolicy = data.toObject());
this.mgmtService.GetLoginPolicy().then(data => {
this.loginPolicy = data.toObject();

View File

@@ -52,8 +52,12 @@
}}</span>
<span class="fill-space"></span>
</div>
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
mat-icon-button>
<button *ngIf="item.projectId !== zitadelProjectId" matTooltip="{{'ACTIONS.DELETE' | translate}}" color="warn"
(click)="deleteProject(item)" class="delete-button" mat-icon-button>
<i class="las la-trash"></i>
</button>
<button matTooltip="{{'ACTIONS.PIN' | translate}}" [ngClass]="{ selected: selection.isSelected(item)}"
(click)="selection.toggle(item)" class="edit-button" mat-icon-button>
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
</button>

View File

@@ -112,6 +112,20 @@
}
}
.delete-button {
opacity: 0;
user-select: none;
position: absolute;
bottom: 0;
right: 30px;
margin: 0;
margin-bottom: .25rem;
&:not(:hover) {
color: #8795a1;
}
}
.edit-button {
opacity: 0;
user-select: none;
@@ -130,12 +144,14 @@
&:hover {
box-shadow: 0 5px 10px rgba(0, 0, 0, .12);
.delete-button,
.edit-button {
opacity: 1;
}
}
&.selected {
.delete-button,
.edit-button {
opacity: 1;
}

View File

@@ -1,11 +1,14 @@
import { animate, animateChild, keyframes, query, stagger, style, transition, trigger } from '@angular/animations';
import { SelectionModel } from '@angular/cdk/collections';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { Org } from 'src/app/proto/generated/auth_pb';
import { ProjectState, ProjectType, ProjectView } from 'src/app/proto/generated/management_pb';
import { AuthenticationService } from 'src/app/services/authentication.service';
import { ManagementService } from 'src/app/services/mgmt.service';
import { StorageKey, StorageService } from 'src/app/services/storage.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'app-owned-project-grid',
@@ -48,8 +51,14 @@ export class OwnedProjectGridComponent implements OnChanges {
public showNewProject: boolean = false;
public ProjectState: any = ProjectState;
public ProjectType: any = ProjectType;
constructor(private router: Router, private authService: AuthenticationService, private storage: StorageService) {
@Input() public zitadelProjectId: string = '';
constructor(
private router: Router,
private dialog: MatDialog,
private storage: StorageService,
private mgmtService: ManagementService,
private toast: ToastService,
) {
this.selection.changed.subscribe(selection => {
this.setPrefixedItem('pinned-projects', JSON.stringify(
this.selection.selected.map(item => item.projectId),
@@ -123,4 +132,30 @@ export class OwnedProjectGridComponent implements OnChanges {
public closeGridView(): void {
this.changedView.emit(true);
}
public deleteProject(item: ProjectView.AsObject): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
if (resp && item.projectId !== this.zitadelProjectId) {
this.mgmtService.RemoveProject(item.projectId).then(() => {
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
const index = this.items.findIndex(iter => iter.projectId === item.projectId);
if (index > -1) {
this.items.splice(index, 1);
}
}).catch(error => {
this.toast.showError(error);
});
}
});
}
}

View File

@@ -1,5 +1,6 @@
<app-owned-project-grid *ngIf="grid" [loading]="loading$ | async" (changedView)="grid = false"
[items]="ownedProjectList || []" (newClicked)="addProject()">
<app-owned-project-grid [zitadelProjectId]="zitadelProjectId" *ngIf="grid && zitadelProjectId"
[loading]="loading$ | async" (changedView)="grid = false" [items]="ownedProjectList || []"
(newClicked)="addProject()">
</app-owned-project-grid>
<div *ngIf="!grid" class="view-toggle">
@@ -61,6 +62,16 @@
</td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let project">
<button *ngIf="project.projectId !== zitadelProjectId" color="warn" mat-icon-button
matTooltip="{{'ACTIONS.DELETE' | translate}}" (click)="deleteProject(project.projectId)">
<i class="las la-trash"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;"
[routerLink]="['/projects', row.projectId]"></tr>

View File

@@ -1,12 +1,14 @@
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
import { SelectionModel } from '@angular/cdk/collections';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { ProjectView } from 'src/app/proto/generated/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@@ -45,7 +47,7 @@ export class OwnedProjectListComponent implements OnInit, OnDestroy {
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public ownedProjectList: ProjectView.AsObject[] = [];
public displayedColumns: string[] = ['select', 'name', 'state', 'creationDate', 'changeDate'];
public displayedColumns: string[] = ['select', 'name', 'state', 'creationDate', 'changeDate', 'actions'];
public selection: SelectionModel<ProjectView.AsObject> = new SelectionModel<ProjectView.AsObject>(true, []);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
@@ -54,11 +56,18 @@ export class OwnedProjectListComponent implements OnInit, OnDestroy {
public grid: boolean = true;
private subscription?: Subscription;
public zitadelProjectId: string = '';
constructor(private router: Router,
public translate: TranslateService,
private mgmtService: ManagementService,
private toast: ToastService,
) { }
private dialog: MatDialog,
) {
this.mgmtService.GetIam().then(iam => {
this.zitadelProjectId = iam.toObject().iamProjectId;
});
}
public ngOnInit(): void {
this.getData(10, 0);
@@ -140,4 +149,29 @@ export class OwnedProjectListComponent implements OnInit, OnDestroy {
this.selection.clear();
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
}
public deleteProject(item: ProjectView.AsObject): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'PROJECT.PAGES.DIALOG.DELETE.TITLE',
descriptionKey: 'PROJECT.PAGES.DIALOG.DELETE.DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe(resp => {
if (this.zitadelProjectId && resp && item.projectId !== this.zitadelProjectId) {
this.mgmtService.RemoveProject(item.projectId).then(() => {
this.toast.showInfo('PROJECT.TOAST.DELETED', true);
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch(error => {
this.toast.showError(error);
});
}
});
}
}

View File

@@ -20,6 +20,7 @@ import { CardModule } from 'src/app/modules/card/card.module';
import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { UserGrantsModule } from 'src/app/modules/user-grants/user-grants.module';
import { WarnDialogModule } from 'src/app/modules/warn-dialog/warn-dialog.module';
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module';
import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module';
@@ -51,6 +52,7 @@ import { OwnedProjectsComponent } from './owned-projects.component';
MatInputModule,
MatChipsModule,
MatIconModule,
WarnDialogModule,
MatButtonModule,
MatProgressSpinnerModule,
MatProgressBarModule,

View File

@@ -37,6 +37,16 @@
<td mat-cell *matCellDef="let idp"> {{idp?.externalUserId}} </td>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let idp">
<button mat-icon-button matTooltip="{{'ACTIONS.REMOVE' | translate}}"
(click)="removeExternalIdp(idp)">
<i class="las la-trash"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;">
</tr>

View File

@@ -1,8 +1,10 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { BehaviorSubject, Observable } from 'rxjs';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { ExternalIDPView as AuthExternalIDPView } from '../../../../proto/generated/auth_pb';
import {
@@ -29,9 +31,9 @@ export class ExternalIdpsComponent implements OnInit {
= new SelectionModel<MgmtExternalIDPView.AsObject | AuthExternalIDPView.AsObject>(true, []);
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
@Input() public displayedColumns: string[] = ['idpConfigId', 'idpName', 'externalUserId', 'externalUserDisplayName'];
@Input() public displayedColumns: string[] = ['idpConfigId', 'idpName', 'externalUserId', 'externalUserDisplayName', 'actions'];
constructor(private toast: ToastService) { }
constructor(private toast: ToastService, private dialog: MatDialog) { }
ngOnInit(): void {
this.getData(10, 0);
@@ -80,19 +82,35 @@ export class ExternalIdpsComponent implements OnInit {
}
public removeExternalIdp(idp: AuthExternalIDPView.AsObject | MgmtExternalIDPView.AsObject): void {
let promise;
if (this.service instanceof ManagementService) {
promise = (this.service as ManagementService).RemoveExternalIDP(idp.externalUserId, idp.idpConfigId, idp.userId);
} else if (this.service instanceof GrpcAuthService) {
promise = (this.service as GrpcAuthService).RemoveExternalIDP(idp.externalUserId, idp.idpConfigId);
}
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.REMOVE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'USER.EXTERNALIDP.DIALOG.DELETE_TITLE',
descriptionKey: 'USER.EXTERNALIDP.DIALOG.DELETE_DESCRIPTION',
},
width: '400px',
});
if (promise) {
promise.then(_ => {
this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize);
}).catch((error: any) => {
this.toast.showError(error);
});
}
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
let promise;
if (this.service instanceof ManagementService) {
promise = (this.service as ManagementService)
.RemoveExternalIDP(idp.externalUserId, idp.idpConfigId, idp.userId);
} else if (this.service instanceof GrpcAuthService) {
promise = (this.service as GrpcAuthService)
.RemoveExternalIDP(idp.externalUserId, idp.idpConfigId);
}
if (promise) {
promise.then(_ => {
this.refreshPage();
}).catch((error: any) => {
this.toast.showError(error);
});
}
}
});
}
}

View File

@@ -9,6 +9,14 @@ import {
CreateUserRequest,
DefaultLoginPolicy,
DefaultLoginPolicyView,
DefaultPasswordAgePolicyRequest,
DefaultPasswordAgePolicyView,
DefaultPasswordComplexityPolicy,
DefaultPasswordComplexityPolicyRequest,
DefaultPasswordComplexityPolicyView,
DefaultPasswordLockoutPolicy,
DefaultPasswordLockoutPolicyRequest,
DefaultPasswordLockoutPolicyView,
FailedEventID,
FailedEvents,
IamMember,
@@ -31,6 +39,7 @@ import {
OrgIamPolicy,
OrgIamPolicyID,
OrgIamPolicyRequest,
OrgIamPolicyView,
OrgSetUpRequest,
OrgSetUpResponse,
RemoveIamMemberRequest,
@@ -91,6 +100,70 @@ export class AdminService {
return this.grpcService.admin.removeFailedEvent(req);
}
/* Policies */
/* complexity */
public GetDefaultPasswordComplexityPolicy(): Promise<DefaultPasswordComplexityPolicyView> {
const req = new Empty();
return this.grpcService.admin.getDefaultPasswordComplexityPolicy(req);
}
public UpdateDefaultPasswordComplexityPolicy(
hasLowerCase: boolean,
hasUpperCase: boolean,
hasNumber: boolean,
hasSymbol: boolean,
minLength: number,
): Promise<DefaultPasswordComplexityPolicy> {
const req = new DefaultPasswordComplexityPolicyRequest();
req.setHasLowercase(hasLowerCase);
req.setHasUppercase(hasUpperCase);
req.setHasNumber(hasNumber);
req.setHasSymbol(hasSymbol);
req.setMinLength(minLength);
return this.grpcService.admin.updateDefaultPasswordComplexityPolicy(req);
}
/* age */
public GetDefaultPasswordAgePolicy(): Promise<DefaultPasswordAgePolicyView> {
const req = new Empty();
return this.grpcService.admin.getDefaultPasswordAgePolicy(req);
}
public UpdateDefaultPasswordAgePolicy(
maxAgeDays: number,
expireWarnDays: number,
): Promise<DefaultPasswordAgePolicyView> {
const req = new DefaultPasswordAgePolicyRequest();
req.setMaxAgeDays(maxAgeDays);
req.setExpireWarnDays(expireWarnDays);
return this.grpcService.admin.updateDefaultPasswordAgePolicy(req);
}
/* lockout */
public GetDefaultPasswordLockoutPolicy(): Promise<DefaultPasswordLockoutPolicyView> {
const req = new Empty();
return this.grpcService.admin.getDefaultPasswordLockoutPolicy(req);
}
public UpdateDefaultPasswordLockoutPolicy(
maxAttempts: number,
showLockoutFailures: boolean,
): Promise<DefaultPasswordLockoutPolicy> {
const req = new DefaultPasswordLockoutPolicyRequest();
req.setMaxAttempts(maxAttempts);
req.setShowLockoutFailure(showLockoutFailures);
return this.grpcService.admin.updateDefaultPasswordLockoutPolicy(req);
}
/* login */
public GetDefaultLoginPolicy(
): Promise<DefaultLoginPolicyView> {
const req = new Empty();
@@ -101,6 +174,50 @@ export class AdminService {
return this.grpcService.admin.updateDefaultLoginPolicy(req);
}
/* org iam */
public GetOrgIamPolicy(orgId: string): Promise<OrgIamPolicyView> {
const req = new OrgIamPolicyID();
req.setOrgId(orgId);
return this.grpcService.admin.getOrgIamPolicy(req);
}
public CreateOrgIamPolicy(
orgId: string,
userLoginMustBeDomain: boolean): Promise<OrgIamPolicy> {
const req = new OrgIamPolicyRequest();
req.setOrgId(orgId);
req.setUserLoginMustBeDomain(userLoginMustBeDomain);
return this.grpcService.admin.createOrgIamPolicy(req);
}
public UpdateOrgIamPolicy(
orgId: string,
userLoginMustBeDomain: boolean): Promise<OrgIamPolicy> {
const req = new OrgIamPolicyRequest();
req.setOrgId(orgId);
req.setUserLoginMustBeDomain(userLoginMustBeDomain);
return this.grpcService.admin.updateOrgIamPolicy(req);
}
public RemoveOrgIamPolicy(
orgId: string,
): Promise<Empty> {
const req = new OrgIamPolicyID();
req.setOrgId(orgId);
return this.grpcService.admin.removeOrgIamPolicy(req);
}
/* admin iam */
public GetDefaultOrgIamPolicy(): Promise<OrgIamPolicyView> {
const req = new Empty();
return this.grpcService.admin.getDefaultOrgIamPolicy(req);
}
/* policies end */
public AddIdpProviderToDefaultLoginPolicy(configId: string): Promise<IdpProviderID> {
const req = new IdpProviderID();
req.setIdpConfigId(configId);
@@ -236,42 +353,4 @@ export class AdminService {
return this.grpcService.admin.changeIamMember(req);
}
public GetOrgIamPolicy(orgId: string): Promise<OrgIamPolicy> {
const req = new OrgIamPolicyID();
req.setOrgId(orgId);
return this.grpcService.admin.getOrgIamPolicy(req);
}
public CreateOrgIamPolicy(
orgId: string,
description: string,
userLoginMustBeDomain: boolean): Promise<OrgIamPolicy> {
const req = new OrgIamPolicyRequest();
req.setOrgId(orgId);
req.setDescription(description);
req.setUserLoginMustBeDomain(userLoginMustBeDomain);
return this.grpcService.admin.createOrgIamPolicy(req);
}
public UpdateOrgIamPolicy(
orgId: string,
description: string,
userLoginMustBeDomain: boolean): Promise<OrgIamPolicy> {
const req = new OrgIamPolicyRequest();
req.setOrgId(orgId);
req.setDescription(description);
req.setUserLoginMustBeDomain(userLoginMustBeDomain);
return this.grpcService.admin.updateOrgIamPolicy(req);
}
public deleteOrgIamPolicy(
orgId: string,
): Promise<Empty> {
const req = new OrgIamPolicyID();
req.setOrgId(orgId);
return this.grpcService.admin.deleteOrgIamPolicy(req);
}
}

View File

@@ -41,6 +41,7 @@ import {
IdpView,
LoginName,
LoginPolicy,
LoginPolicyRequest,
LoginPolicyView,
MachineKeyIDRequest,
MachineKeySearchRequest,
@@ -64,24 +65,20 @@ import {
OrgDomainValidationRequest,
OrgDomainValidationResponse,
OrgDomainValidationType,
OrgIamPolicy,
OrgIamPolicyView,
OrgMember,
OrgMemberRoles,
OrgMemberSearchRequest,
OrgMemberSearchResponse,
OrgView,
PasswordAgePolicy,
PasswordAgePolicyCreate,
PasswordAgePolicyID,
PasswordAgePolicyUpdate,
PasswordAgePolicyRequest,
PasswordAgePolicyView,
PasswordComplexityPolicy,
PasswordComplexityPolicyCreate,
PasswordComplexityPolicyID,
PasswordComplexityPolicyUpdate,
PasswordComplexityPolicyRequest,
PasswordComplexityPolicyView,
PasswordLockoutPolicy,
PasswordLockoutPolicyCreate,
PasswordLockoutPolicyID,
PasswordLockoutPolicyUpdate,
PasswordLockoutPolicyRequest,
PasswordRequest,
PrimaryOrgDomainRequest,
Project,
@@ -188,10 +185,14 @@ export class ManagementService {
return this.grpcService.mgmt.getLoginPolicy(req);
}
public UpdateLoginPolicy(req: LoginPolicy): Promise<LoginPolicy> {
public UpdateLoginPolicy(req: LoginPolicyRequest): Promise<LoginPolicy> {
return this.grpcService.mgmt.updateLoginPolicy(req);
}
public CreateLoginPolicy(req: LoginPolicyRequest): Promise<LoginPolicy> {
return this.grpcService.mgmt.createLoginPolicy(req);
}
public RemoveLoginPolicy(): Promise<Empty> {
return this.grpcService.mgmt.removeLoginPolicy(new Empty());
}
@@ -498,63 +499,56 @@ export class ManagementService {
// Policy
public GetMyOrgIamPolicy(): Promise<OrgIamPolicy> {
public GetMyOrgIamPolicy(): Promise<OrgIamPolicyView> {
const req = new Empty();
return this.grpcService.mgmt.getMyOrgIamPolicy(req);
}
public GetPasswordAgePolicy(): Promise<PasswordAgePolicy> {
public GetPasswordAgePolicy(): Promise<PasswordAgePolicyView> {
const req = new Empty();
return this.grpcService.mgmt.getPasswordAgePolicy(req);
}
public CreatePasswordAgePolicy(
description: string,
maxAgeDays: number,
expireWarnDays: number,
): Promise<PasswordAgePolicy> {
const req = new PasswordAgePolicyCreate();
req.setDescription(description);
const req = new PasswordAgePolicyRequest();
req.setMaxAgeDays(maxAgeDays);
req.setExpireWarnDays(expireWarnDays);
return this.grpcService.mgmt.createPasswordAgePolicy(req);
}
public DeletePasswordAgePolicy(id: string): Promise<Empty> {
const req = new PasswordAgePolicyID();
req.setId(id);
return this.grpcService.mgmt.deletePasswordAgePolicy(req);
public RemovePasswordAgePolicy(): Promise<Empty> {
const req = new Empty();
return this.grpcService.mgmt.removePasswordAgePolicy(req);
}
public UpdatePasswordAgePolicy(
description: string,
maxAgeDays: number,
expireWarnDays: number,
): Promise<PasswordAgePolicy> {
const req = new PasswordAgePolicyUpdate();
req.setDescription(description);
const req = new PasswordAgePolicyRequest();
req.setMaxAgeDays(maxAgeDays);
req.setExpireWarnDays(expireWarnDays);
return this.grpcService.mgmt.updatePasswordAgePolicy(req);
}
public GetPasswordComplexityPolicy(): Promise<PasswordComplexityPolicy> {
public GetPasswordComplexityPolicy(): Promise<PasswordComplexityPolicyView> {
const req = new Empty();
return this.grpcService.mgmt.getPasswordComplexityPolicy(req);
}
public CreatePasswordComplexityPolicy(
description: string,
hasLowerCase: boolean,
hasUpperCase: boolean,
hasNumber: boolean,
hasSymbol: boolean,
minLength: number,
): Promise<PasswordComplexityPolicy> {
const req = new PasswordComplexityPolicyCreate();
req.setDescription(description);
const req = new PasswordComplexityPolicyRequest();
req.setHasLowercase(hasLowerCase);
req.setHasUppercase(hasUpperCase);
req.setHasNumber(hasNumber);
@@ -563,22 +557,19 @@ export class ManagementService {
return this.grpcService.mgmt.createPasswordComplexityPolicy(req);
}
public DeletePasswordComplexityPolicy(id: string): Promise<Empty> {
const req = new PasswordComplexityPolicyID();
req.setId(id);
return this.grpcService.mgmt.deletePasswordComplexityPolicy(req);
public removePasswordComplexityPolicy(): Promise<Empty> {
const req = new Empty();
return this.grpcService.mgmt.removePasswordComplexityPolicy(req);
}
public UpdatePasswordComplexityPolicy(
description: string,
hasLowerCase: boolean,
hasUpperCase: boolean,
hasNumber: boolean,
hasSymbol: boolean,
minLength: number,
): Promise<PasswordComplexityPolicy> {
const req = new PasswordComplexityPolicyUpdate();
req.setDescription(description);
const req = new PasswordComplexityPolicy();
req.setHasLowercase(hasLowerCase);
req.setHasUppercase(hasUpperCase);
req.setHasNumber(hasNumber);
@@ -594,34 +585,28 @@ export class ManagementService {
}
public CreatePasswordLockoutPolicy(
description: string,
maxAttempts: number,
showLockoutFailures: boolean,
): Promise<PasswordLockoutPolicy> {
const req = new PasswordLockoutPolicyCreate();
req.setDescription(description);
const req = new PasswordLockoutPolicyRequest();
req.setMaxAttempts(maxAttempts);
req.setShowLockOutFailures(showLockoutFailures);
req.setShowLockoutFailure(showLockoutFailures);
return this.grpcService.mgmt.createPasswordLockoutPolicy(req);
}
public DeletePasswordLockoutPolicy(id: string): Promise<Empty> {
const req = new PasswordLockoutPolicyID();
req.setId(id);
return this.grpcService.mgmt.deletePasswordLockoutPolicy(req);
public RemovePasswordLockoutPolicy(): Promise<Empty> {
const req = new Empty();
return this.grpcService.mgmt.removePasswordLockoutPolicy(req);
}
public UpdatePasswordLockoutPolicy(
description: string,
maxAttempts: number,
showLockoutFailures: boolean,
): Promise<PasswordLockoutPolicy> {
const req = new PasswordLockoutPolicyUpdate();
req.setDescription(description);
const req = new PasswordLockoutPolicy();
req.setMaxAttempts(maxAttempts);
req.setShowLockOutFailures(showLockoutFailures);
req.setShowLockoutFailure(showLockoutFailures);
return this.grpcService.mgmt.updatePasswordLockoutPolicy(req);
}

View File

@@ -61,6 +61,7 @@
"REFRESH":"Aktualisieren",
"LOGIN":"Einloggen",
"EDIT":"Bearbeiten",
"PIN":"Anpinnen",
"CONFIGURE":"Konfigurieren"
},
"ERRORS": {
@@ -139,7 +140,11 @@
"IDPCONFIGID": "Idp Konfig ID",
"IDPNAME": "Idp Name",
"USERDISPLAYNAME": "Externer Name",
"EXTERNALUSERID": "Externe Benutzer ID"
"EXTERNALUSERID": "Externe Benutzer ID",
"DIALOG": {
"REMOVE_TITLE":"Idp entfernen",
"REMOVE_DESCRIPTION":"Sie sind im Begriff einen Identity Provider zu entfernen. Wollen Sie dies wirklich tun?"
}
},
"CREATE": {
"TITLE": "Neuen Benutzer erstellen",
@@ -443,9 +448,11 @@
"TITLE":"Login Richtlinien",
"DESCRIPTION":"Definiere die Loginmethoden für Benutzer",
"TITLECREATE":"Definiere die Loginmethoden für Benutzer",
"DESCRIPTIONCREATEADMIN":"Nutzer können Sich mit den verfügbaren Idps authentifizieren.",
"DESCRIPTIONCREATEMGMT":"Nutzer können Sich mit den verfügbaren Idps authentifizieren. Achtung: Es kann von System-, sowie von selbsterstellten Providern Ihrer Organisation gewählt werden."
"DESCRIPTIONCREATEADMIN":"Nutzer können sich mit den verfügbaren Idps authentifizieren.",
"DESCRIPTIONCREATEMGMT":"Nutzer können sich mit den verfügbaren Idps authentifizieren. Achtung: Es kann zwischen System- und organisationsspezifischen Providern gewählt werden.",
"SAVED":"Erfolgreich gespeichert."
},
"DEFAULTLABEL":"Die aktuelle Richtlinie entspricht der IAM-Standard Einstellung.",
"BTN_INSTALL":"Installieren",
"BTN_EDIT":"Modifizieren",
"DATA": {
@@ -464,7 +471,11 @@
"ALLOWEXTERNALIDP":"Externer IDP erlaubt",
"ALLOWREGISTER":"Registrieren erlaubt"
},
"DELETE":"Richtlinie entfernen/zurücksetzen"
"RESET":"Richtlinie zurücksetzen",
"TOAST":{
"SET":"Richtline erfolgreich gesetzt!",
"RESETSUCCESS":"Richtline zurückgesetzt!"
}
},
"TOAST": {
"DEACTIVATED":"Organisation deaktiviert.",

View File

@@ -61,6 +61,7 @@
"REFRESH":"Refresh",
"LOGIN":"Login",
"EDIT":"Edit",
"PIN":"Pin / Unpin",
"CONFIGURE":"Configure"
},
"ERRORS": {
@@ -139,7 +140,11 @@
"IDPCONFIGID": "Idp Config ID",
"IDPNAME": "Idp Name",
"USERDISPLAYNAME": "External Name",
"EXTERNALUSERID": "External User ID"
"EXTERNALUSERID": "External User ID",
"DIALOG": {
"REMOVE_TITLE":"Remove IDP",
"REMOVE_DESCRIPTION":"You are about to delete an Identity Provider from a user. Do you really want to continue?"
}
},
"CREATE": {
"TITLE": "Create a New User",
@@ -444,8 +449,10 @@
"DESCRIPTION":"Define how Users can be authenticated",
"TITLECREATE":"Define how Users can be authenticated",
"DESCRIPTIONCREATEADMIN":"Users can choose from the available identity providers below.",
"DESCRIPTIONCREATEMGMT":"Users can choose from the available identity providers below. Note: You can use System-set providers as well as providers set for your organisation only."
"DESCRIPTIONCREATEMGMT":"Users can choose from the available identity providers below. Note: You can use System-set providers as well as providers set for your organisation only.",
"SAVED":"Saved successfully!"
},
"DEFAULTLABEL":"The currently set guideline corresponds to the standard setting set by the IAM Administrator.",
"BTN_INSTALL":"Setup",
"BTN_EDIT":"Modify",
"DATA": {
@@ -464,7 +471,11 @@
"ALLOWEXTERNALIDP":"External IDP allowed",
"ALLOWREGISTER":"Register allowed"
},
"DELETE":"Uninstall/Reset Policy"
"RESET":"Reset Policy",
"TOAST":{
"SET":"Policy set successfully!",
"RESETSUCCESS":"Policy reset successfully!"
}
},
"TOAST": {
"DEACTIVATED":"Organisation deactivated.",