mirror of
https://github.com/zitadel/zitadel.git
synced 2025-10-20 12:22:25 +00:00
feat(console): identity providers and login policies (#722)
* idp list, idp create route * idp modules, lazy import, i18n, routing * generic service, i18n * seperate lockout, age policy component * seperate component modules * routing * enum class * login policy * iam policy grid * login policy providers * idps login policy * add idp dialog component * add idp to loginpolicy * delete idp config, iam policy grid * remove idp from loginpolicy * idp detail component, generic idp create * lint * idp detail clientid-secrets, issuer, scopes * hide clientsecret on update * rm background style, idp config * app tooltip fix * lint * dont refresh on idp select * Update console/src/app/modules/idp-create/idp-create.component.html Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<h1 mat-dialog-title>
|
||||
<span class="title">{{'LOGINPOLICY.ADDIDP.TITLE' | translate}}</span>
|
||||
</h1>
|
||||
<p class="desc"> {{'LOGINPOLICY.ADDIDP.DESCRIPTION' | translate}}</p>
|
||||
|
||||
<div mat-dialog-content>
|
||||
<mat-form-field *ngIf="serviceType == PolicyComponentServiceType.MGMT" class="full-width" appearance="outline">
|
||||
<mat-label>{{ 'IDP.TYPE' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="idpType" (selectionChange)="loadIdps()" (selectionChange)="loadIdps()">
|
||||
<mat-option *ngFor="let type of idpTypes" [value]="type">
|
||||
{{ 'IDP.TYPES.'+type | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<p>{{'LOGINPOLICY.ADDIDP.SELECTIDPS' | translate}}</p>
|
||||
|
||||
<mat-form-field class="full-width" appearance="outline">
|
||||
<mat-label>{{ 'LOGINPOLICY.ADDIDP.SELECTIDPS' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="idp">
|
||||
<mat-option *ngFor="let idp of availableIdps" [value]="idp">
|
||||
{{ idp.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-button (click)="closeDialog()">
|
||||
{{'ACTIONS.CANCEL' | translate}}
|
||||
</button>
|
||||
|
||||
<button [disabled]="!idp || !idpType " color="primary" mat-raised-button class="ok-button"
|
||||
(click)="closeDialogWithSuccess()">
|
||||
{{'ACTIONS.ADD' | translate}}
|
||||
</button>
|
||||
</div>
|
@@ -0,0 +1,25 @@
|
||||
.title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddIdpDialogComponent } from './add-idp-dialog.component';
|
||||
|
||||
|
||||
describe('AddIdpDialogComponent', () => {
|
||||
let component: AddIdpDialogComponent;
|
||||
let fixture: ComponentFixture<AddIdpDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AddIdpDialogComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AddIdpDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,84 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { IdpView as AdminIdpView } from 'src/app/proto/generated/admin_pb';
|
||||
import {
|
||||
Idp,
|
||||
IdpProviderType,
|
||||
IdpSearchKey,
|
||||
IdpSearchQuery,
|
||||
IdpView as MgmtIdpView,
|
||||
SearchMethod,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-idp-dialog',
|
||||
templateUrl: './add-idp-dialog.component.html',
|
||||
styleUrls: ['./add-idp-dialog.component.scss'],
|
||||
})
|
||||
export class AddIdpDialogComponent {
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
|
||||
public idpType!: IdpProviderType;
|
||||
public idpTypes: IdpProviderType[] = [
|
||||
IdpProviderType.IDPPROVIDERTYPE_SYSTEM,
|
||||
IdpProviderType.IDPPROVIDERTYPE_ORG,
|
||||
];
|
||||
|
||||
public idp: Idp.AsObject | undefined = undefined;
|
||||
public availableIdps: Array<AdminIdpView.AsObject | MgmtIdpView.AsObject> | string[] = [];
|
||||
public IdpProviderType: any = IdpProviderType;
|
||||
|
||||
constructor(
|
||||
private mgmtService: ManagementService,
|
||||
private adminService: AdminService,
|
||||
public dialogRef: MatDialogRef<AddIdpDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
) {
|
||||
if (data.serviceType) {
|
||||
this.serviceType = data.serviceType;
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.idpType = IdpProviderType.IDPPROVIDERTYPE_ORG;
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.idpType = IdpProviderType.IDPPROVIDERTYPE_SYSTEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.loadIdps();
|
||||
}
|
||||
|
||||
public loadIdps(): void {
|
||||
this.idp = undefined;
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const query: IdpSearchQuery = new IdpSearchQuery();
|
||||
query.setKey(IdpSearchKey.IDPSEARCHKEY_PROVIDER_TYPE);
|
||||
query.setMethod(SearchMethod.SEARCHMETHOD_EQUALS);
|
||||
query.setValue(this.idpType.toString());
|
||||
this.mgmtService.SearchIdps().then(idps => {
|
||||
this.availableIdps = idps.toObject().resultList;
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
this.adminService.SearchIdps().then(idps => {
|
||||
this.availableIdps = idps.toObject().resultList;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
|
||||
public closeDialogWithSuccess(): void {
|
||||
this.dialogRef.close({
|
||||
idp: this.idp,
|
||||
type: this.idpType,
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { AddIdpDialogComponent } from './add-idp-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AddIdpDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
TranslateModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
FormsModule,
|
||||
],
|
||||
})
|
||||
export class AddIdpDialogModule { }
|
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: LoginPolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class LoginPolicyRoutingModule { }
|
@@ -0,0 +1,51 @@
|
||||
<app-detail-layout [backRouterLink]="[ '/org']" [title]="'ORG.POLICY.LOGIN_POLICY.TITLECREATE' | translate"
|
||||
[description]="'ORG.POLICY.LOGIN_POLICY.DESCRIPTIONCREATE' | translate">
|
||||
<ng-container *ngIf="(['policy.delete'] | hasRole | async) && serviceType == PolicyComponentServiceType.MGMT">
|
||||
<button matTooltip="{{'ORG.POLICY.DELETE' | translate}}" color="warn" (click)="deletePolicy()"
|
||||
mat-stroked-button>
|
||||
{{'ORG.POLICY.DELETE' | translate}}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<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">
|
||||
</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">
|
||||
</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
|
||||
[(ngModel)]="loginData.allowExternalIdp">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="subheader">{{'LOGINPOLICY.IDPS' | translate}}</p>
|
||||
|
||||
<div class="idps">
|
||||
<div class="idp" *ngFor="let idp of idps">
|
||||
<mat-icon (click)="removeIdp(idp)" class="rm">remove_circle</mat-icon>
|
||||
<p>{{idp.name}}</p>
|
||||
<span>{{idp.type}}</span>
|
||||
<span>{{idp.configId}}</span>
|
||||
</div>
|
||||
<div class="new-idp" (click)="openDialog()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
@@ -0,0 +1,85 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.subheader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.idps {
|
||||
display: flex;
|
||||
margin: 0 -.5rem;
|
||||
|
||||
.idp,
|
||||
.new-idp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: .5rem;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
border: 1px solid #8795a1;
|
||||
border-radius: .5rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
.rm {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #ffffff10;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: scale-down;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
|
||||
describe('LoginPolicyComponent', () => {
|
||||
let component: LoginPolicyComponent;
|
||||
let fixture: ComponentFixture<LoginPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LoginPolicyComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginPolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,179 @@
|
||||
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 { Subscription } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
DefaultLoginPolicy,
|
||||
DefaultLoginPolicyView,
|
||||
IdpProviderView as AdminIdpProviderView,
|
||||
IdpView as AdminIdpView,
|
||||
} from 'src/app/proto/generated/admin_pb';
|
||||
import {
|
||||
IdpProviderType,
|
||||
IdpProviderView as MgmtIdpProviderView,
|
||||
IdpView as MgmtIdpView,
|
||||
LoginPolicy,
|
||||
LoginPolicyView,
|
||||
} 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 { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { AddIdpDialogComponent } from './add-idp-dialog/add-idp-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login-policy',
|
||||
templateUrl: './login-policy.component.html',
|
||||
styleUrls: ['./login-policy.component.scss'],
|
||||
})
|
||||
export class LoginPolicyComponent implements OnDestroy {
|
||||
public loginData!: LoginPolicy.AsObject | DefaultLoginPolicy.AsObject;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
private service!: ManagementService | AdminService;
|
||||
PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
public idps: MgmtIdpProviderView.AsObject[] | AdminIdpProviderView.AsObject[] = [];
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
private injector: Injector,
|
||||
) {
|
||||
this.sub = this.route.data.pipe(switchMap(data => {
|
||||
console.log(data.serviceType);
|
||||
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.loginData = data.toObject();
|
||||
}
|
||||
});
|
||||
this.getIdps().then(idps => {
|
||||
console.log(idps);
|
||||
this.idps = idps;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData():
|
||||
Promise<LoginPolicyView | DefaultLoginPolicyView> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
return (this.service as ManagementService).GetLoginPolicy();
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
return (this.service as AdminService).GetDefaultLoginPolicy();
|
||||
}
|
||||
}
|
||||
|
||||
private async getIdps(): Promise<MgmtIdpProviderView.AsObject[] | AdminIdpProviderView.AsObject[]> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
return (this.service as ManagementService).GetLoginPolicyIdpProviders()
|
||||
.then((providers) => {
|
||||
return providers.toObject().resultList;
|
||||
});
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
return (this.service as AdminService).GetDefaultLoginPolicyIdpProviders()
|
||||
.then((providers) => {
|
||||
return providers.toObject().resultList;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async updateData():
|
||||
Promise<LoginPolicy | DefaultLoginPolicy> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
const mgmtreq = new LoginPolicy();
|
||||
mgmtreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
|
||||
mgmtreq.setAllowRegister(this.loginData.allowRegister);
|
||||
mgmtreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
|
||||
return (this.service as ManagementService).UpdateLoginPolicy(mgmtreq);
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
const adminreq = new DefaultLoginPolicy();
|
||||
adminreq.setAllowExternalIdp(this.loginData.allowExternalIdp);
|
||||
adminreq.setAllowRegister(this.loginData.allowRegister);
|
||||
adminreq.setAllowUsernamePassword(this.loginData.allowUsernamePassword);
|
||||
return (this.service as AdminService).UpdateDefaultLoginPolicy(adminreq);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}).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 openDialog(): void {
|
||||
const dialogRef = this.dialog.open(AddIdpDialogComponent, {
|
||||
data: {
|
||||
serviceType: this.serviceType,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp && resp.idp && resp.type) {
|
||||
this.addIdp(resp.idp, resp.type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private addIdp(idp: AdminIdpView.AsObject | MgmtIdpView.AsObject,
|
||||
type: IdpProviderType = IdpProviderType.IDPPROVIDERTYPE_SYSTEM): Promise<any> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
return (this.service as ManagementService).addIdpProviderToLoginPolicy(idp.id, type);
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
return (this.service as AdminService).AddIdpProviderToDefaultLoginPolicy(idp.id);
|
||||
}
|
||||
}
|
||||
|
||||
public removeIdp(idp: AdminIdpView.AsObject | MgmtIdpView.AsObject): void {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
(this.service as ManagementService).RemoveIdpProviderFromLoginPolicy(idp.id);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
(this.service as AdminService).RemoveIdpProviderFromDefaultLoginPolicy(idp.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe.module';
|
||||
|
||||
import { AddIdpDialogModule } from './add-idp-dialog/add-idp-dialog.module';
|
||||
import { LoginPolicyRoutingModule } from './login-policy-routing.module';
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LoginPolicyComponent],
|
||||
imports: [
|
||||
LoginPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRolePipeModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
AddIdpDialogModule,
|
||||
],
|
||||
})
|
||||
export class LoginPolicyModule { }
|
@@ -0,0 +1,30 @@
|
||||
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 = [
|
||||
{
|
||||
path: '',
|
||||
component: PasswordAgePolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.MODIFY,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: PasswordAgePolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.CREATE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class PasswordAgePolicyRoutingModule { }
|
@@ -0,0 +1,48 @@
|
||||
<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="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>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementExpireWarnDays()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{ageData?.expireWarnDays}}</span>
|
||||
<button mat-icon-button (click)="decrementExpireWarnDays()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.MAXAGEDAYS' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementMaxAgeDays()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{ageData?.maxAgeDays}}</span>
|
||||
<button mat-icon-button (click)="decrementMaxAgeDays()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
@@ -0,0 +1,44 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordAgePolicyComponent } from './password-age-policy.component';
|
||||
|
||||
describe('PasswordAgePolicyComponent', () => {
|
||||
let component: PasswordAgePolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordAgePolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordAgePolicyComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordAgePolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,126 @@
|
||||
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 { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentAction } from '../policy-component-action.enum';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-age-policy',
|
||||
templateUrl: './password-age-policy.component.html',
|
||||
styleUrls: ['./password-age-policy.component.scss'],
|
||||
})
|
||||
export class PasswordAgePolicyComponent implements OnDestroy {
|
||||
public title: string = '';
|
||||
public desc: string = '';
|
||||
|
||||
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
|
||||
|
||||
public PolicyComponentAction: any = PolicyComponentAction;
|
||||
|
||||
public ageData!: PasswordAgePolicy.AsObject;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private mgmtService: ManagementService,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
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();
|
||||
}
|
||||
|
||||
public deletePolicy(): void {
|
||||
this.mgmtService.DeletePasswordAgePolicy(this.ageData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public incrementExpireWarnDays(): void {
|
||||
if (this.ageData?.expireWarnDays !== undefined) {
|
||||
this.ageData.expireWarnDays++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementExpireWarnDays(): void {
|
||||
if (this.ageData?.expireWarnDays && this.ageData?.expireWarnDays > 0) {
|
||||
this.ageData.expireWarnDays--;
|
||||
}
|
||||
}
|
||||
|
||||
public incrementMaxAgeDays(): void {
|
||||
if (this.ageData?.maxAgeDays !== undefined) {
|
||||
this.ageData.maxAgeDays++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementMaxAgeDays(): void {
|
||||
if (this.ageData?.maxAgeDays && this.ageData?.maxAgeDays > 0) {
|
||||
this.ageData.maxAgeDays--;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
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 { PasswordAgePolicyRoutingModule } from './password-age-policy-routing.module';
|
||||
import { PasswordAgePolicyComponent } from './password-age-policy.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PasswordAgePolicyComponent],
|
||||
imports: [
|
||||
PasswordAgePolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
})
|
||||
export class PasswordAgePolicyModule { }
|
@@ -0,0 +1,30 @@
|
||||
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 = [
|
||||
{
|
||||
path: '',
|
||||
component: PasswordComplexityPolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.MODIFY,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: PasswordComplexityPolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.CREATE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class PasswordComplexityPolicyRoutingModule { }
|
@@ -0,0 +1,60 @@
|
||||
<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 *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>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="decrementLength()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
<span>{{complexityData?.minLength}}</span>
|
||||
<button mat-icon-button (click)="incrementLength()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASNUMBER' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="complexityData.hasNumber">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASSYMBOL' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasSymbol" ngDefaultControl [(ngModel)]="complexityData.hasSymbol">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASLOWERCASE' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasLowercase" ngDefaultControl
|
||||
[(ngModel)]="complexityData.hasLowercase">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="left-desc">{{'ORG.POLICY.DATA.HASUPPERCASE' | translate}}</span>
|
||||
<span class="fill-space"></span>
|
||||
<mat-slide-toggle color="primary" name="hasUppercase" ngDefaultControl
|
||||
[(ngModel)]="complexityData.hasUppercase">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit" [disabled]="!complexityData?.description"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
@@ -0,0 +1,44 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
|
||||
|
||||
describe('PasswordComplexityPolicyComponent', () => {
|
||||
let component: PasswordComplexityPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordComplexityPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordComplexityPolicyComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordComplexityPolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,119 @@
|
||||
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 { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentAction } from '../policy-component-action.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-policy',
|
||||
templateUrl: './password-complexity-policy.component.html',
|
||||
styleUrls: ['./password-complexity-policy.component.scss'],
|
||||
})
|
||||
export class PasswordComplexityPolicyComponent implements OnDestroy {
|
||||
public title: string = '';
|
||||
public desc: string = '';
|
||||
|
||||
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
|
||||
|
||||
public PolicyComponentAction: any = PolicyComponentAction;
|
||||
|
||||
public complexityData!: PasswordComplexityPolicy.AsObject;
|
||||
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private mgmtService: ManagementService,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
) {
|
||||
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';
|
||||
|
||||
if (this.componentAction === PolicyComponentAction.MODIFY) {
|
||||
this.getData(params).then(data => {
|
||||
if (data) {
|
||||
this.complexityData = data.toObject() as PasswordComplexityPolicy.AsObject;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
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();
|
||||
}
|
||||
|
||||
public deletePolicy(): void {
|
||||
this.mgmtService.DeletePasswordComplexityPolicy(this.complexityData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public incrementLength(): void {
|
||||
if (this.complexityData?.minLength !== undefined && this.complexityData?.minLength <= 72) {
|
||||
this.complexityData.minLength++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementLength(): void {
|
||||
if (this.complexityData?.minLength && this.complexityData?.minLength > 1) {
|
||||
this.complexityData.minLength--;
|
||||
}
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
if (this.componentAction === PolicyComponentAction.CREATE) {
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
} 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
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 { PasswordComplexityPolicyRoutingModule } from './password-complexity-policy-routing.module';
|
||||
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PasswordComplexityPolicyComponent],
|
||||
imports: [
|
||||
PasswordComplexityPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
})
|
||||
export class PasswordComplexityPolicyModule { }
|
@@ -0,0 +1,30 @@
|
||||
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 { }
|
@@ -0,0 +1,28 @@
|
||||
<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>
|
@@ -0,0 +1,44 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordIamPolicyComponent } from './password-iam-policy.component';
|
||||
|
||||
describe('PasswordIamPolicyComponent', () => {
|
||||
let component: PasswordIamPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordIamPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordIamPolicyComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordIamPolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,102 @@
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
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';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PasswordIamPolicyComponent],
|
||||
imports: [
|
||||
PasswordIamPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
})
|
||||
export class PasswordIamPolicyModule { }
|
@@ -0,0 +1,30 @@
|
||||
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 = [
|
||||
{
|
||||
path: '',
|
||||
component: PasswordLockoutPolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.MODIFY,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: PasswordLockoutPolicyComponent,
|
||||
data: {
|
||||
animation: 'DetailPage',
|
||||
action: PolicyComponentAction.CREATE,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class PasswordLockoutPolicyRoutingModule { }
|
@@ -0,0 +1,41 @@
|
||||
<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="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>
|
||||
<div class="length-wrapper">
|
||||
<button mat-icon-button (click)="incrementMaxAttempts()">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<span>{{lockoutData?.maxAttempts}}</span>
|
||||
<button mat-icon-button (click)="decrementMaxAttempts()">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</div>
|
||||
</app-detail-layout>
|
@@ -0,0 +1,44 @@
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
|
||||
.left-desc {
|
||||
color: #8795a1;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.length-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-top: 3rem;
|
||||
display: block;
|
||||
padding: .5rem 4rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component';
|
||||
|
||||
describe('PasswordLockoutPolicyComponent', () => {
|
||||
let component: PasswordLockoutPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordLockoutPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordLockoutPolicyComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordLockoutPolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,113 @@
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
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 { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentAction } from '../policy-component-action.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-password-lockout-policy',
|
||||
templateUrl: './password-lockout-policy.component.html',
|
||||
styleUrls: ['./password-lockout-policy.component.scss'],
|
||||
})
|
||||
export class PasswordLockoutPolicyComponent implements OnDestroy {
|
||||
public title: string = '';
|
||||
public desc: string = '';
|
||||
|
||||
componentAction: PolicyComponentAction = PolicyComponentAction.CREATE;
|
||||
|
||||
public PolicyComponentAction: any = PolicyComponentAction;
|
||||
|
||||
public lockoutForm!: FormGroup;
|
||||
public lockoutData!: PasswordLockoutPolicy.AsObject;
|
||||
private sub: Subscription = new Subscription();
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private mgmtService: ManagementService,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
) {
|
||||
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';
|
||||
|
||||
if (this.componentAction === PolicyComponentAction.MODIFY) {
|
||||
this.getData(params).then(data => {
|
||||
if (data) {
|
||||
this.lockoutData = data.toObject() as PasswordLockoutPolicy.AsObject;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
private async getData(params: any):
|
||||
Promise<PasswordLockoutPolicy | PasswordAgePolicy | PasswordComplexityPolicy | OrgIamPolicy | undefined> {
|
||||
|
||||
this.title = 'ORG.POLICY.PWD_LOCKOUT.TITLE';
|
||||
this.desc = 'ORG.POLICY.PWD_LOCKOUT.DESCRIPTION';
|
||||
return this.mgmtService.GetPasswordLockoutPolicy();
|
||||
}
|
||||
|
||||
public deletePolicy(): void {
|
||||
this.mgmtService.DeletePasswordLockoutPolicy(this.lockoutData.id).then(() => {
|
||||
this.toast.showInfo('Successfully deleted');
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public incrementMaxAttempts(): void {
|
||||
if (this.lockoutData?.maxAttempts !== undefined) {
|
||||
this.lockoutData.maxAttempts++;
|
||||
}
|
||||
}
|
||||
|
||||
public decrementMaxAttempts(): void {
|
||||
if (this.lockoutData?.maxAttempts && this.lockoutData?.maxAttempts > 0) {
|
||||
this.lockoutData.maxAttempts--;
|
||||
}
|
||||
}
|
||||
|
||||
public savePolicy(): void {
|
||||
if (this.componentAction === PolicyComponentAction.CREATE) {
|
||||
this.mgmtService.CreatePasswordLockoutPolicy(
|
||||
this.lockoutData.description,
|
||||
this.lockoutData.maxAttempts,
|
||||
this.lockoutData.showLockOutFailures,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.componentAction === PolicyComponentAction.MODIFY) {
|
||||
|
||||
this.mgmtService.UpdatePasswordLockoutPolicy(
|
||||
this.lockoutData.description,
|
||||
this.lockoutData.maxAttempts,
|
||||
this.lockoutData.showLockOutFailures,
|
||||
).then(() => {
|
||||
this.router.navigate(['org']);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
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 { PasswordLockoutPolicyRoutingModule } from './password-lockout-policy-routing.module';
|
||||
import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PasswordLockoutPolicyComponent],
|
||||
imports: [
|
||||
PasswordLockoutPolicyRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonModule,
|
||||
MatSlideToggleModule,
|
||||
MatIconModule,
|
||||
HasRoleModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
],
|
||||
})
|
||||
export class PasswordLockoutPolicyModule { }
|
@@ -0,0 +1,5 @@
|
||||
|
||||
export enum PolicyComponentAction {
|
||||
CREATE = 'create',
|
||||
MODIFY = 'modify',
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
export enum PolicyComponentType {
|
||||
LOCKOUT = 'lockout',
|
||||
AGE = 'age',
|
||||
COMPLEXITY = 'complexity',
|
||||
IAM = 'iam',
|
||||
LOGIN = 'login',
|
||||
}
|
||||
export enum PolicyComponentServiceType {
|
||||
MGMT = 'mgmt',
|
||||
ADMIN = 'admin',
|
||||
}
|
Reference in New Issue
Block a user