mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-26 17:22:15 +00:00
feat(console): Google, Generic OIDC, Generic JWT - Identity provider templates (#5265)
implement Google, Generic OIDC, Generic JWT provider templates in console
This commit is contained in:
@@ -1,174 +0,0 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ 'IDP.CREATE.TITLE' | translate }}"
|
||||
[createSteps]="createSteps"
|
||||
[currentCreateStep]="currentCreateStep"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="idp-create-content">
|
||||
<h1>{{ 'IDP.CREATE.TITLE' | translate }}</h1>
|
||||
|
||||
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 1">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.CREATE.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<cnsl-idp-type-radio [types]="idpTypes" (selectedType)="idpType = $event" [selected]="idpType"> </cnsl-idp-type-radio>
|
||||
|
||||
<div class="first-step-actions">
|
||||
<button mat-raised-button [disabled]="!idpType" color="primary" (click)="currentCreateStep = 2">
|
||||
{{ 'ACTIONS.CONTINUE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === OIDC">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.OIDC.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="oidcFormGroup" (ngSubmit)="addOIDCIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="autoRegister">
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-card class="scope-card">
|
||||
<div class="idp-scopes">
|
||||
<div class="flex-line">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</cnsl-card>
|
||||
</div>
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="idpDisplayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="oidcFormGroup.invalid" type="submit">
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentCreateStep === 2 && idpType === JWT">
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.JWT.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="jwtFormGroup" (ngSubmit)="addJWTIdp()">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtHeaderName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtIssuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="jwtAutoRegister">
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtKeysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="idp-create-actions">
|
||||
<button color="primary" (click)="currentCreateStep = 1" mat-stroked-button class="back-button" type="button">
|
||||
{{ 'ACTIONS.BACK' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="jwtFormGroup.invalid" type="submit">
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
||||
@@ -1,345 +0,0 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, OnDestroy, OnInit, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { AddJWTIDPRequest, AddOIDCIDPRequest } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { OIDCMappingField } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import { AddOrgJWTIDPRequest, AddOrgOIDCIDPRequest } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||
import { JWT, OIDC, RadioItemIdpType } from './idptypes';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-idp-create',
|
||||
templateUrl: './idp-create.component.html',
|
||||
styleUrls: ['./idp-create.component.scss'],
|
||||
})
|
||||
export class IdpCreateComponent implements OnInit, OnDestroy {
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
public mappingFields: OIDCMappingField[] = [];
|
||||
|
||||
private subscription?: Subscription;
|
||||
public projectId: string = '';
|
||||
|
||||
public oidcFormGroup!: UntypedFormGroup;
|
||||
public jwtFormGroup!: UntypedFormGroup;
|
||||
|
||||
public createSteps: number = 2;
|
||||
public currentCreateStep: number = 1;
|
||||
public loading: boolean = false;
|
||||
|
||||
public idpTypes: RadioItemIdpType[] = [OIDC, JWT];
|
||||
|
||||
OIDC: any = OIDC;
|
||||
JWT: any = JWT;
|
||||
|
||||
public idpType!: RadioItemIdpType;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private _location: Location,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.oidcFormGroup = new UntypedFormGroup({
|
||||
name: new UntypedFormControl('', [Validators.required]),
|
||||
clientId: new UntypedFormControl('', [Validators.required]),
|
||||
clientSecret: new UntypedFormControl('', [Validators.required]),
|
||||
issuer: new UntypedFormControl('', [Validators.required]),
|
||||
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
|
||||
idpDisplayNameMapping: new UntypedFormControl(0),
|
||||
usernameMapping: new UntypedFormControl(0),
|
||||
autoRegister: new UntypedFormControl(false),
|
||||
});
|
||||
|
||||
this.jwtFormGroup = new UntypedFormGroup({
|
||||
jwtName: new UntypedFormControl('', [Validators.required]),
|
||||
jwtHeaderName: new UntypedFormControl('', [Validators.required]),
|
||||
jwtIssuer: new UntypedFormControl('', [Validators.required]),
|
||||
jwtEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
jwtKeysEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
jwtStylingType: new UntypedFormControl(0),
|
||||
jwtAutoRegister: new UntypedFormControl(false),
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
this.mappingFields = [
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL,
|
||||
];
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
this.mappingFields = [
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL,
|
||||
];
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe((params) => this.getData(params));
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private getData({ projectid }: Params): void {
|
||||
this.projectId = projectid;
|
||||
}
|
||||
|
||||
public addOIDCIdp(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new AddOrgOIDCIDPRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
|
||||
req.setUsernameMapping(this.usernameMapping?.value);
|
||||
req.setAutoRegister(this.autoRegister?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addOrgOIDCIDP(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(
|
||||
[
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? '/org-settings'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? '/settings'
|
||||
: '',
|
||||
],
|
||||
{ queryParams: { id: 'idp' } },
|
||||
);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AddOIDCIDPRequest();
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setDisplayNameMapping(this.idpDisplayNameMapping?.value);
|
||||
req.setUsernameMapping(this.usernameMapping?.value);
|
||||
req.setAutoRegister(this.autoRegister?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addOIDCIDP(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(
|
||||
[
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? '/org-settings'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? '/settings'
|
||||
: '',
|
||||
],
|
||||
{ queryParams: { id: 'idp' } },
|
||||
);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public addJWTIdp(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new AddOrgJWTIDPRequest();
|
||||
|
||||
req.setName(this.jwtName?.value);
|
||||
req.setHeaderName(this.jwtHeaderName?.value);
|
||||
req.setIssuer(this.jwtIssuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.jwtKeysEndpoint?.value);
|
||||
req.setAutoRegister(this.jwtAutoRegister?.value);
|
||||
req.setStylingType(this.jwtStylingType?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addOrgJWTIDP(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate([
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam'
|
||||
: '',
|
||||
'policy',
|
||||
'login',
|
||||
]);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AddJWTIDPRequest();
|
||||
|
||||
req.setName(this.jwtName?.value);
|
||||
req.setHeaderName(this.jwtHeaderName?.value);
|
||||
req.setIssuer(this.jwtIssuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.jwtKeysEndpoint?.value);
|
||||
req.setAutoRegister(this.jwtAutoRegister?.value);
|
||||
req.setStylingType(this.jwtStylingType?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addJWTIDP(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate([
|
||||
this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org'
|
||||
: this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam'
|
||||
: '',
|
||||
'policy',
|
||||
'login',
|
||||
]);
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public addScope(event: MatChipInputEvent): void {
|
||||
const input = event.chipInput?.inputElement;
|
||||
const value = event.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (this.scopesList?.value) {
|
||||
this.scopesList.value.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeScope(uri: string): void {
|
||||
if (this.scopesList?.value) {
|
||||
const index = this.scopesList.value.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.scopesList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('name');
|
||||
}
|
||||
|
||||
public get clientId(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('clientId');
|
||||
}
|
||||
|
||||
public get clientSecret(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('clientSecret');
|
||||
}
|
||||
|
||||
public get issuer(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('issuer');
|
||||
}
|
||||
|
||||
public get scopesList(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('scopesList');
|
||||
}
|
||||
|
||||
public get autoRegister(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('autoRegister');
|
||||
}
|
||||
|
||||
public get idpDisplayNameMapping(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('idpDisplayNameMapping');
|
||||
}
|
||||
|
||||
public get usernameMapping(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('usernameMapping');
|
||||
}
|
||||
|
||||
public get jwtName(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtName');
|
||||
}
|
||||
|
||||
public get jwtHeaderName(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtHeaderName');
|
||||
}
|
||||
|
||||
public get jwtIssuer(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtIssuer');
|
||||
}
|
||||
|
||||
public get jwtEndpoint(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtEndpoint');
|
||||
}
|
||||
|
||||
public get jwtKeysEndpoint(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtKeysEndpoint');
|
||||
}
|
||||
|
||||
public get jwtStylingType(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtStylingType');
|
||||
}
|
||||
|
||||
public get jwtAutoRegister(): AbstractControl | null {
|
||||
return this.jwtFormGroup.get('jwtAutoRegister');
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<div class="idp-radio-button-wrapper">
|
||||
<ng-container *ngFor="let type of types">
|
||||
<input
|
||||
class="idp mat-elevation-z1"
|
||||
type="radio"
|
||||
(change)="emitChange()"
|
||||
[value]="type"
|
||||
[(ngModel)]="selected"
|
||||
[id]="type.titleI18nKey"
|
||||
/>
|
||||
<label class="cnsl-idp-type-radio-button" [for]="type.titleI18nKey">
|
||||
<div class="cnsl-idp-type-radio-header">
|
||||
<mat-icon class="icon" *ngIf="type.mdi" [svgIcon]="type.mdi"></mat-icon>
|
||||
<span class="fill-space"></span>
|
||||
<span>{{ type.titleI18nKey | translate }}</span>
|
||||
</div>
|
||||
</label>
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -1,60 +0,0 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
.idp-radio-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -0.5rem;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
@mixin idp-type-radio-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat.get-color-from-palette($primary, 500);
|
||||
$primary-color-light: mat.get-color-from-palette($primary, 300);
|
||||
$primary-color-dark: mat.get-color-from-palette($primary, 700);
|
||||
$primary-color-contrast: mat.get-color-from-palette($primary, default-contrast);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$back: map-get($theme, background);
|
||||
$fg: map-get($theme, foreground);
|
||||
$cardback: map-get($back, cards);
|
||||
$text: map-get($fg, text);
|
||||
$border-color: if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
|
||||
|
||||
input[type='radio'].idp {
|
||||
appearance: none;
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cnsl-idp-type-radio-button {
|
||||
margin: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background-color: $cardback;
|
||||
border: 1px solid $border-color;
|
||||
box-sizing: border-box;
|
||||
|
||||
.cnsl-idp-type-radio-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 1rem;
|
||||
|
||||
span {
|
||||
margin: 1rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.idp:checked + label {
|
||||
border: 1px solid if($is-dark-theme, $primary-color-dark, $primary-color-light) !important;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
import { OIDC, RadioItemIdpType } from '../idptypes';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-idp-type-radio',
|
||||
templateUrl: './idp-type-radio.component.html',
|
||||
styleUrls: ['./idp-type-radio.component.scss'],
|
||||
})
|
||||
export class IdpTypeRadioComponent {
|
||||
@Input() selected: RadioItemIdpType = OIDC;
|
||||
@Input() types!: RadioItemIdpType[];
|
||||
@Output() selectedType: EventEmitter<RadioItemIdpType> = new EventEmitter();
|
||||
|
||||
public emitChange(): void {
|
||||
this.selectedType.emit(this.selected);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
export enum IdpCreateType {
|
||||
OIDC = 'OIDC',
|
||||
JWT = 'JWT',
|
||||
}
|
||||
|
||||
export interface RadioItemIdpType {
|
||||
createType: IdpCreateType;
|
||||
titleI18nKey: string;
|
||||
mdi?: string;
|
||||
}
|
||||
|
||||
export const OIDC = {
|
||||
titleI18nKey: 'IDP.OIDC.TITLE',
|
||||
mdi: 'mdi_openid',
|
||||
createType: IdpCreateType.OIDC,
|
||||
};
|
||||
|
||||
export const JWT = {
|
||||
titleI18nKey: 'IDP.JWT.TITLE',
|
||||
mdi: 'mdi_jwt',
|
||||
createType: IdpCreateType.JWT,
|
||||
};
|
||||
@@ -7,100 +7,8 @@
|
||||
[selection]="selection"
|
||||
[hideRefresh]="true"
|
||||
>
|
||||
<div actions>
|
||||
<button
|
||||
(click)="deactivateSelectedIdps()"
|
||||
matTooltip="{{ 'IDP.DEACTIVATE' | translate }}"
|
||||
class="idp-margin-right bg-state inactive"
|
||||
mat-stroked-button
|
||||
*ngIf="selection.hasValue()"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.idp.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org.idp.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'IDP.DEACTIVATE' | translate }}
|
||||
</button>
|
||||
<button
|
||||
(click)="reactivateSelectedIdps()"
|
||||
matTooltip="{{ 'IDP.ACTIVATE' | translate }}"
|
||||
class="bg-state active"
|
||||
mat-stroked-button
|
||||
*ngIf="selection.hasValue()"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.idp.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org.idp.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'IDP.ACTIVATE' | translate }}
|
||||
</button>
|
||||
|
||||
<a
|
||||
[routerLink]="createRouterLink"
|
||||
class="cnsl-action-button"
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.idp.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org.idp.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="table" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox
|
||||
color="primary"
|
||||
(change)="$event ? masterToggle() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
[disabled]="serviceType === PolicyComponentServiceType.MGMT"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let idp">
|
||||
<mat-checkbox
|
||||
color="primary"
|
||||
(click)="$event.stopPropagation()"
|
||||
class="chbox"
|
||||
[disabled]="serviceType === PolicyComponentServiceType.MGMT && idp?.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM"
|
||||
(change)="$event ? selection.toggle(idp) : null"
|
||||
[checked]="selection.isSelected(idp)"
|
||||
>
|
||||
<img
|
||||
src="../../../assets/images/google.png"
|
||||
*ngIf="idp.stylingType === IDPStylingType.IDPSTYLINGTYPE_GOOGLE"
|
||||
alt="google"
|
||||
/>
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="availability">
|
||||
<th class="availability" mat-header-cell *matHeaderCellDef>
|
||||
<span>{{ 'IDP.AVAILABILITY' | translate }}</span>
|
||||
@@ -129,8 +37,21 @@
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'IDP.TYPE' | translate }}</th>
|
||||
<td class="pointer" [routerLink]="routerLinkForRow(idp)" mat-cell *matCellDef="let idp">
|
||||
<span class="state" *ngIf="idp?.oidcConfig">{{ 'IDP.TYPES.1' | translate }}</span>
|
||||
<span class="state" *ngIf="idp?.jwtConfig">{{ 'IDP.TYPES.3' | translate }}</span>
|
||||
<div [ngSwitch]="idp.type">
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_GOOGLE">
|
||||
<img class="idp-logo" src="../../../assets/images/idp/google.png" alt="google" />
|
||||
Google
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_OIDC">
|
||||
<mat-icon class="idp-icon" svgIcon="mdi_openid" alt="oidc" />
|
||||
Generic OIDC
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_JWT">
|
||||
<mat-icon class="idp-icon" svgIcon="mdi_jwt" alt="jwt" />
|
||||
Generic JWT
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchDefault>coming soon</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -150,21 +71,21 @@
|
||||
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'IDP.CREATIONDATE' | translate }}</th>
|
||||
<td [routerLink]="routerLinkForRow(idp)" class="pointer" mat-cell *matCellDef="let idp">
|
||||
<td class="pointer" [routerLink]="routerLinkForRow(idp)" mat-cell *matCellDef="let idp">
|
||||
<span>{{ idp.details.creationDate | timestampToDate | localizedDate : 'dd. MMM, HH:mm' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="changeDate">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'IDP.CHANGEDATE' | translate }}</th>
|
||||
<td [routerLink]="routerLinkForRow(idp)" class="pointer" mat-cell *matCellDef="let idp">
|
||||
<td class="pointer" [routerLink]="routerLinkForRow(idp)" mat-cell *matCellDef="let idp">
|
||||
<span>{{ idp.details.changeDate | timestampToDate | localizedDate : 'dd. MMM, HH:mm' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="owner">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'IDP.OWNER' | translate }}</th>
|
||||
<td [routerLink]="routerLinkForRow(idp)" class="pointer" mat-cell *matCellDef="let idp">
|
||||
<td class="pointer" [routerLink]="routerLinkForRow(idp)" mat-cell *matCellDef="let idp">
|
||||
{{ 'IDP.OWNERTYPES.' + idp.owner | translate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,3 +1,44 @@
|
||||
@mixin idp-table-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$warn: map-get($theme, warn);
|
||||
$background: map-get($theme, background);
|
||||
$accent: map-get($theme, accent);
|
||||
$primary-color: mat.get-color-from-palette($primary, 500);
|
||||
|
||||
$warn-color: mat.get-color-from-palette($warn, 500);
|
||||
$accent-color: mat.get-color-from-palette($accent, 500);
|
||||
$foreground: map-get($theme, foreground);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$back: map-get($background, background);
|
||||
|
||||
.idp-table-provider-type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.idp-logo {
|
||||
margin-right: 1rem;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.dark {
|
||||
display: if($is-dark-theme, block, none);
|
||||
}
|
||||
|
||||
&.light {
|
||||
display: if($is-dark-theme, none, block);
|
||||
}
|
||||
}
|
||||
|
||||
.idp-icon {
|
||||
font-size: 1.75rem;
|
||||
height: 1.75rem;
|
||||
width: 1.75rem;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.idp-margin-right {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -6,13 +6,26 @@ import { RouterLink } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { ListIDPsResponse } from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { IDP, IDPLoginPolicyLink, IDPOwnerType, IDPState, IDPStylingType } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
ListProvidersRequest as AdminListProvidersRequest,
|
||||
ListProvidersResponse as AdminListProvidersResponse,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import {
|
||||
IDP,
|
||||
IDPLoginPolicyLink,
|
||||
IDPOwnerType,
|
||||
IDPState,
|
||||
IDPStylingType,
|
||||
Provider,
|
||||
ProviderType,
|
||||
} from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
AddCustomLoginPolicyRequest,
|
||||
AddCustomLoginPolicyResponse,
|
||||
ListOrgIDPsResponse,
|
||||
ListProvidersRequest as MgmtListProvidersRequest,
|
||||
ListProvidersResponse as MgmtListProvidersResponse,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { ListQuery } from 'src/app/proto/generated/zitadel/object_pb';
|
||||
import { LoginPolicy } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
@@ -31,16 +44,17 @@ export class IdpTableComponent implements OnInit {
|
||||
@Input() public serviceType!: PolicyComponentServiceType;
|
||||
@Input() service!: AdminService | ManagementService;
|
||||
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
|
||||
public dataSource: MatTableDataSource<IDP.AsObject> = new MatTableDataSource<IDP.AsObject>();
|
||||
public selection: SelectionModel<IDP.AsObject> = new SelectionModel<IDP.AsObject>(true, []);
|
||||
public idpResult?: ListIDPsResponse.AsObject | ListOrgIDPsResponse.AsObject;
|
||||
public dataSource: MatTableDataSource<Provider.AsObject> = new MatTableDataSource<Provider.AsObject>();
|
||||
public selection: SelectionModel<Provider.AsObject> = new SelectionModel<Provider.AsObject>(true, []);
|
||||
public idpResult?: MgmtListProvidersResponse.AsObject | AdminListProvidersResponse.AsObject;
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public IDPOwnerType: any = IDPOwnerType;
|
||||
public IDPState: any = IDPState;
|
||||
public displayedColumns: string[] = ['availability', 'name', 'type', 'creationDate', 'changeDate', 'state', 'actions'];
|
||||
@Output() public changedSelection: EventEmitter<Array<IDP.AsObject>> = new EventEmitter();
|
||||
public ProviderType: any = ProviderType;
|
||||
public displayedColumns: string[] = ['availability', 'name', 'type', 'creationDate', 'changeDate', 'actions'];
|
||||
@Output() public changedSelection: EventEmitter<Array<Provider.AsObject>> = new EventEmitter();
|
||||
|
||||
public idps: IDPLoginPolicyLink.AsObject[] = [];
|
||||
public IDPStylingType: any = IDPStylingType;
|
||||
@@ -59,7 +73,7 @@ export class IdpTableComponent implements OnInit {
|
||||
});
|
||||
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
this.displayedColumns = ['availability', 'name', 'type', 'owner', 'creationDate', 'changeDate', 'state', 'actions'];
|
||||
this.displayedColumns = ['availability', 'name', 'type', 'owner', 'creationDate', 'changeDate', 'actions'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +175,13 @@ export class IdpTableComponent implements OnInit {
|
||||
this.loadingSubject.next(true);
|
||||
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtListProvidersRequest();
|
||||
const lq = new ListQuery();
|
||||
lq.setOffset(offset);
|
||||
lq.setLimit(limit);
|
||||
req.setQuery(lq);
|
||||
(this.service as ManagementService)
|
||||
.listOrgIDPs(limit, offset)
|
||||
.listProviders(req)
|
||||
.then((resp) => {
|
||||
this.idpResult = resp;
|
||||
this.dataSource.data = resp.resultList;
|
||||
@@ -173,8 +192,13 @@ export class IdpTableComponent implements OnInit {
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
} else {
|
||||
const req = new AdminListProvidersRequest();
|
||||
const lq = new ListQuery();
|
||||
lq.setOffset(offset);
|
||||
lq.setLimit(limit);
|
||||
req.setQuery(lq);
|
||||
(this.service as AdminService)
|
||||
.listIDPs(limit, offset)
|
||||
.listProviders(req)
|
||||
.then((resp) => {
|
||||
this.idpResult = resp;
|
||||
this.dataSource.data = resp.resultList;
|
||||
@@ -199,19 +223,15 @@ export class IdpTableComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public routerLinkForRow(row: IDP.AsObject): any {
|
||||
public routerLinkForRow(row: Provider.AsObject): any {
|
||||
if (row.id) {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
switch (row.owner) {
|
||||
case IDPOwnerType.IDP_OWNER_TYPE_SYSTEM:
|
||||
return ['/instance', 'idp', row.id];
|
||||
case IDPOwnerType.IDP_OWNER_TYPE_ORG:
|
||||
return ['/org', 'idp', row.id];
|
||||
}
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
return ['/instance', 'idp', row.id];
|
||||
switch (row.type) {
|
||||
case ProviderType.PROVIDER_TYPE_OIDC:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'oidc', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_JWT:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'jwt', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_GOOGLE:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'google', row.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,7 +298,7 @@ export class IdpTableComponent implements OnInit {
|
||||
return (this.service as ManagementService).addCustomLoginPolicy(mgmtreq);
|
||||
}
|
||||
|
||||
public addIdp(idp: IDP.AsObject | IDP.AsObject): Promise<any> {
|
||||
public addIdp(idp: Provider.AsObject): Promise<any> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
if (this.isDefault) {
|
||||
@@ -307,13 +327,15 @@ export class IdpTableComponent implements OnInit {
|
||||
.addIDPToLoginPolicy(idp.id, idp.owner)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.ADDED', true);
|
||||
this.getIdps()
|
||||
.then((resp) => {
|
||||
this.idps = resp;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.getIdps()
|
||||
.then((resp) => {
|
||||
this.idps = resp;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
@@ -324,9 +346,15 @@ export class IdpTableComponent implements OnInit {
|
||||
.addIDPToLoginPolicy(idp.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.ADDED', true);
|
||||
this.getIdps().then((resp) => {
|
||||
this.idps = resp;
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.getIdps()
|
||||
.then((resp) => {
|
||||
this.idps = resp;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
@@ -334,7 +362,7 @@ export class IdpTableComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public removeIdp(idp: IDP.AsObject): Promise<any> {
|
||||
public removeIdp(idp: Provider.AsObject): Promise<any> {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
if (this.isDefault) {
|
||||
@@ -367,9 +395,15 @@ export class IdpTableComponent implements OnInit {
|
||||
.removeIDPFromLoginPolicy(idp.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.REMOVED', true);
|
||||
this.getIdps().then((resp) => {
|
||||
this.idps = resp;
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.getIdps()
|
||||
.then((resp) => {
|
||||
this.idps = resp;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
@@ -380,9 +414,15 @@ export class IdpTableComponent implements OnInit {
|
||||
.removeIDPFromLoginPolicy(idp.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.REMOVED', true);
|
||||
this.getIdps().then((resp) => {
|
||||
this.idps = resp;
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.getIdps()
|
||||
.then((resp) => {
|
||||
this.idps = resp;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
@@ -390,7 +430,7 @@ export class IdpTableComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public isEnabled(idp: IDP.AsObject): boolean {
|
||||
public isEnabled(idp: Provider.AsObject): boolean {
|
||||
return this.idps.findIndex((i) => i.idpId === idp.id) > -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
<cnsl-top-view
|
||||
title="{{ idp?.name ? idp?.name : ('IDP.DETAIL.TITLE' | translate) }}"
|
||||
[sub]="idp?.oidcConfig ? ('IDP.TYPES.1' | translate) : idp?.jwtConfig ? ('IDP.TYPES.3' | translate) : ''"
|
||||
[isActive]="idp?.state === IDPState.IDP_STATE_ACTIVE"
|
||||
[isInactive]="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
[hasContributors]="false"
|
||||
stateTooltip="{{ 'IDP.STATES.' + idp?.state | translate }}"
|
||||
[hasActions]="(serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']) | hasRole | async"
|
||||
>
|
||||
<ng-template
|
||||
topActions
|
||||
cnslHasRole
|
||||
[hasRole]="serviceType === PolicyComponentServiceType.MGMT ? ['org.idp.write'] : ['iam.idp.write']"
|
||||
>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="idp?.state !== IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_INACTIVE)"
|
||||
>
|
||||
{{ 'ACTIONS.DEACTIVATE' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="idp?.state === IDPState.IDP_STATE_INACTIVE"
|
||||
(click)="changeState(IDPState.IDP_STATE_ACTIVE)"
|
||||
>
|
||||
{{ 'ACTIONS.REACTIVATE' | translate }}
|
||||
</button>
|
||||
<button mat-menu-item matTooltip="{{ 'IDP.DELETE' | translate }}" (click)="deleteIdp()">
|
||||
<span [style.color]="'var(--warn)'">{{ 'IDP.DELETE_TITLE' | translate }}</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
<cnsl-info-row topContent *ngIf="idp" [idp]="idp"></cnsl-info-row>
|
||||
</cnsl-top-view>
|
||||
|
||||
<div class="max-width-container">
|
||||
<div class="idp-wrapper">
|
||||
<h2>{{ 'IDP.OIDC.GENERAL' | translate }}</h2>
|
||||
|
||||
<form (ngSubmit)="updateIdp()">
|
||||
<ng-container [formGroup]="idpForm">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.STYLE' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="stylingType">
|
||||
<mat-option *ngFor="let field of styleFields" [value]="field">
|
||||
{{ 'IDP.STYLEFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="auto-reg-desc">{{ 'IDP.AUTOREGISTER_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="autoRegister" [disabled]="(canWrite | async) === false">
|
||||
{{ 'IDP.AUTOREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="idpForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ng-container *ngIf="idp?.oidcConfig && oidcConfigForm">
|
||||
<h2>{{ 'IDP.OIDC.TITLE' | translate }}</h2>
|
||||
<p class="idp-desc cnsl-secondary-text">{{ 'IDP.OIDC.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form (ngSubmit)="updateOidcConfig()">
|
||||
<ng-container [formGroup]="oidcConfigForm">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox
|
||||
class="idp-desc cnsl-secondary-text"
|
||||
[(ngModel)]="showIdSecretSection"
|
||||
[disabled]="(canWrite | async) === false"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
>
|
||||
Update Client Secret
|
||||
</mat-checkbox>
|
||||
|
||||
<cnsl-form-field class="idp-formfield" *ngIf="showIdSecretSection">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-card class="scope-card">
|
||||
<div class="scope-card-content">
|
||||
<div class="flex-line">
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
|
||||
<button (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<mat-chip-list class="chip-list" #chipScopesList aria-label="scope selection">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
[disabled]="(canWrite | async) === false"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</cnsl-card>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.IDPDISPLAYNAMMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="displayNameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.USERNAMEMAPPING' | translate }}</cnsl-label>
|
||||
<mat-select formControlName="usernameMapping">
|
||||
<mat-option *ngFor="let field of mappingFields" [value]="field">
|
||||
{{ 'IDP.MAPPINGFIELD.' + field | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="oidcConfigForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="idp?.jwtConfig && jwtConfigForm">
|
||||
<h2>{{ 'IDP.JWT.TITLE' | translate }}</h2>
|
||||
<p>{{ 'IDP.JWT.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form (ngSubmit)="updateJwtConfig()">
|
||||
<ng-container [formGroup]="jwtConfigForm">
|
||||
<div class="idp-content">
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="headerName" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="idp-formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="keysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<button
|
||||
color="primary"
|
||||
mat-raised-button
|
||||
class="continue-button"
|
||||
[disabled]="jwtConfigForm.invalid || (canWrite | async) === false"
|
||||
type="submit"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,85 +0,0 @@
|
||||
.idp-wrapper {
|
||||
margin-top: 2rem;
|
||||
|
||||
.idp-desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.idp-content {
|
||||
.idp-desc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.idp-formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
|
||||
.chip {
|
||||
border-radius: 0.5rem;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.mat-chip-input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-reg-info {
|
||||
margin: 0 0 1rem 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
|
||||
.auto-reg-desc {
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.scope-card {
|
||||
max-width: 400px;
|
||||
display: block;
|
||||
|
||||
.scope-card-content {
|
||||
display: block;
|
||||
|
||||
.flex-line {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
width: 100%;
|
||||
|
||||
.idp-formfield {
|
||||
flex: 1;
|
||||
|
||||
input {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-wrapper {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
|
||||
.continue-button {
|
||||
margin-bottom: 2rem;
|
||||
display: block;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import {
|
||||
UpdateIDPJWTConfigRequest,
|
||||
UpdateIDPOIDCConfigRequest,
|
||||
UpdateIDPRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { IDP, IDPState, IDPStylingType, OIDCMappingField } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
UpdateOrgIDPJWTConfigRequest,
|
||||
UpdateOrgIDPOIDCConfigRequest,
|
||||
UpdateOrgIDPRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||
import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-idp',
|
||||
templateUrl: './idp.component.html',
|
||||
styleUrls: ['./idp.component.scss'],
|
||||
})
|
||||
export class IdpComponent implements OnDestroy {
|
||||
public mappingFields: OIDCMappingField[] = [];
|
||||
public styleFields: IDPStylingType[] = [];
|
||||
|
||||
public showIdSecretSection: boolean = false;
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
|
||||
public idp?: IDP.AsObject;
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
public projectId: string = '';
|
||||
|
||||
public idpForm!: UntypedFormGroup;
|
||||
public oidcConfigForm!: UntypedFormGroup;
|
||||
public jwtConfigForm!: UntypedFormGroup;
|
||||
|
||||
IDPState: any = IDPState;
|
||||
|
||||
public canWrite: Observable<boolean> = this.authService.isAllowed([
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.idp.write'
|
||||
: this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'org.idp.write'
|
||||
: '',
|
||||
]);
|
||||
|
||||
constructor(
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private _location: Location,
|
||||
private authService: GrpcAuthService,
|
||||
private dialog: MatDialog,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.idpForm = new UntypedFormGroup({
|
||||
id: new UntypedFormControl({ disabled: true, value: '' }, [Validators.required]),
|
||||
name: new UntypedFormControl('', [Validators.required]),
|
||||
stylingType: new UntypedFormControl('', [Validators.required]),
|
||||
autoRegister: new UntypedFormControl(false, [Validators.required]),
|
||||
});
|
||||
|
||||
this.oidcConfigForm = new UntypedFormGroup({
|
||||
clientId: new UntypedFormControl('', [Validators.required]),
|
||||
clientSecret: new UntypedFormControl(''),
|
||||
issuer: new UntypedFormControl('', [Validators.required]),
|
||||
scopesList: new UntypedFormControl([], []),
|
||||
displayNameMapping: new UntypedFormControl(0),
|
||||
usernameMapping: new UntypedFormControl(0),
|
||||
});
|
||||
|
||||
this.jwtConfigForm = new UntypedFormGroup({
|
||||
jwtEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
issuer: new UntypedFormControl('', [Validators.required]),
|
||||
keysEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
headerName: new UntypedFormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
const serviceType = this.route.snapshot.data.serviceType;
|
||||
if (serviceType !== undefined) {
|
||||
this.serviceType = serviceType;
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.INSTANCE,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.mappingFields = [
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
|
||||
OIDCMappingField.OIDC_MAPPING_FIELD_EMAIL,
|
||||
];
|
||||
this.styleFields = [IDPStylingType.STYLING_TYPE_UNSPECIFIED, IDPStylingType.STYLING_TYPE_GOOGLE];
|
||||
}
|
||||
|
||||
const idpId = this.route.snapshot.paramMap.get('id');
|
||||
if (idpId) {
|
||||
this.checkWrite();
|
||||
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
(this.service as ManagementService).getOrgIDPByID(idpId).then((resp) => {
|
||||
if (resp.idp) {
|
||||
this.idp = resp.idp;
|
||||
this.idpForm.patchValue(this.idp);
|
||||
if (this.idp.oidcConfig) {
|
||||
this.oidcConfigForm.patchValue(this.idp.oidcConfig);
|
||||
} else if (this.idp.jwtConfig) {
|
||||
this.jwtConfigForm.patchValue(this.idp.jwtConfig);
|
||||
this.jwtIssuer?.setValue(this.idp.jwtConfig.issuer);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
(this.service as AdminService).getIDPByID(idpId).then((resp) => {
|
||||
if (resp.idp) {
|
||||
this.idp = resp.idp;
|
||||
this.idpForm.patchValue(this.idp);
|
||||
if (this.idp.oidcConfig) {
|
||||
this.oidcConfigForm.patchValue(this.idp.oidcConfig);
|
||||
} else if (this.idp.jwtConfig) {
|
||||
this.jwtConfigForm.patchValue(this.idp.jwtConfig);
|
||||
this.jwtIssuer?.setValue(this.idp.jwtConfig.issuer);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public checkWrite(): void {
|
||||
this.canWrite.pipe(take(1)).subscribe((canWrite) => {
|
||||
if (canWrite) {
|
||||
this.idpForm.enable();
|
||||
this.oidcConfigForm.enable();
|
||||
} else {
|
||||
this.idpForm.disable();
|
||||
this.oidcConfigForm.disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
public deleteIdp(): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'IDP.DELETE_TITLE',
|
||||
descriptionKey: 'IDP.DELETE_DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (this.idp && resp) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
(this.service as ManagementService)
|
||||
.removeOrgIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.DELETED', true);
|
||||
this.router.navigate(this.backroutes);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
(this.service as AdminService)
|
||||
.removeIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.DELETED', true);
|
||||
this.router.navigate(this.backroutes);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public changeState(state: IDPState): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
if (state === IDPState.IDP_STATE_ACTIVE && this.idp) {
|
||||
(this.service as ManagementService)
|
||||
.reactivateOrgIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.idp!.state = state;
|
||||
this.toast.showInfo('IDP.TOAST.REACTIVATED', true);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (state === IDPState.IDP_STATE_INACTIVE && this.idp) {
|
||||
(this.service as ManagementService)
|
||||
.deactivateOrgIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.idp!.state = state;
|
||||
this.toast.showInfo('IDP.TOAST.DEACTIVATED', true);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
if (state === IDPState.IDP_STATE_ACTIVE && this.idp) {
|
||||
(this.service as AdminService)
|
||||
.reactivateIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.idp!.state = state;
|
||||
this.toast.showInfo('IDP.TOAST.REACTIVATED', true);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (state === IDPState.IDP_STATE_INACTIVE && this.idp) {
|
||||
(this.service as AdminService)
|
||||
.deactivateIDP(this.idp.id)
|
||||
.then(() => {
|
||||
this.idp!.state = state;
|
||||
this.toast.showInfo('IDP.TOAST.DEACTIVATED', true);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public updateIdp(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT && this.idp) {
|
||||
const req = new UpdateOrgIDPRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setStylingType(this.stylingType?.value);
|
||||
req.setAutoRegister(this.autoRegister?.value);
|
||||
|
||||
(this.service as ManagementService)
|
||||
.updateOrgIDP(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN && this.idp) {
|
||||
const req = new UpdateIDPRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setStylingType(this.stylingType?.value);
|
||||
req.setAutoRegister(this.autoRegister?.value);
|
||||
|
||||
(this.service as AdminService)
|
||||
.updateIDP(req)
|
||||
.then(() => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateOidcConfig(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT && this.idp) {
|
||||
const req = new UpdateOrgIDPOIDCConfigRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setUsernameMapping(this.usernameMapping?.value);
|
||||
req.setDisplayNameMapping(this.displayNameMapping?.value);
|
||||
|
||||
(this.service as ManagementService)
|
||||
.updateOrgIDPOIDCConfig(req)
|
||||
.then((oidcConfig) => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN && this.idp) {
|
||||
const req = new UpdateIDPOIDCConfigRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setUsernameMapping(this.usernameMapping?.value);
|
||||
req.setDisplayNameMapping(this.displayNameMapping?.value);
|
||||
|
||||
(this.service as AdminService)
|
||||
.updateIDPOIDCConfig(req)
|
||||
.then((oidcConfig) => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateJwtConfig(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT && this.idp) {
|
||||
const req = new UpdateOrgIDPJWTConfigRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setIssuer(this.jwtIssuer?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keyEndpoint?.value);
|
||||
|
||||
(this.service as ManagementService)
|
||||
.updateOrgIDPJWTConfig(req)
|
||||
.then((jwtConfig) => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
// this.router.navigate(['idp', ]);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN && this.idp) {
|
||||
const req = new UpdateIDPJWTConfigRequest();
|
||||
|
||||
req.setIdpId(this.idp.id);
|
||||
req.setIssuer(this.jwtIssuer?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keyEndpoint?.value);
|
||||
|
||||
(this.service as AdminService)
|
||||
.updateIDPJWTConfig(req)
|
||||
.then((jwtConfig) => {
|
||||
this.toast.showInfo('IDP.TOAST.SAVED', true);
|
||||
// this.router.navigate(['idp', ]);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public addScope(event: MatChipInputEvent): void {
|
||||
const input = event.chipInput?.inputElement;
|
||||
const value = event.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (this.scopesList?.value) {
|
||||
this.scopesList.value.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeScope(uri: string): void {
|
||||
if (this.scopesList?.value) {
|
||||
const index = this.scopesList?.value.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.scopesList?.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get backroutes(): string[] {
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
return ['/org', 'policy', 'login'];
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
return ['/instance', 'policy', 'login'];
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.idpForm.get('name');
|
||||
}
|
||||
|
||||
public get stylingType(): AbstractControl | null {
|
||||
return this.idpForm.get('stylingType');
|
||||
}
|
||||
|
||||
public get autoRegister(): AbstractControl | null {
|
||||
return this.idpForm.get('autoRegister');
|
||||
}
|
||||
|
||||
public get clientId(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('clientId');
|
||||
}
|
||||
|
||||
public get clientSecret(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('clientSecret');
|
||||
}
|
||||
|
||||
public get issuer(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('issuer');
|
||||
}
|
||||
|
||||
public get scopesList(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('scopesList');
|
||||
}
|
||||
|
||||
public get displayNameMapping(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('displayNameMapping');
|
||||
}
|
||||
|
||||
public get usernameMapping(): AbstractControl | null {
|
||||
return this.oidcConfigForm.get('usernameMapping');
|
||||
}
|
||||
|
||||
public get jwtIssuer(): AbstractControl | null {
|
||||
return this.jwtConfigForm.get('issuer');
|
||||
}
|
||||
|
||||
public get jwtEndpoint(): AbstractControl | null {
|
||||
return this.jwtConfigForm.get('jwtEndpoint');
|
||||
}
|
||||
|
||||
public get keyEndpoint(): AbstractControl | null {
|
||||
return this.jwtConfigForm.get('keysEndpoint');
|
||||
}
|
||||
|
||||
public get headerName(): AbstractControl | null {
|
||||
return this.jwtConfigForm.get('headerName');
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,86 @@
|
||||
<div class="cnsl-idp-table-wrapper">
|
||||
<cnsl-idp-table [service]="service" [serviceType]="serviceType"></cnsl-idp-table>
|
||||
</div>
|
||||
|
||||
<h2>{{ 'IDP.CREATE.TITLE' | translate }}</h2>
|
||||
<p class="cnsl-secondary-text">{{ 'IDP.CREATE.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div class="new-idp-wrapper">
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['/instance', 'provider', 'google', 'create']
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['/org', 'provider', 'google', 'create']
|
||||
: []
|
||||
"
|
||||
>
|
||||
<img class="idp-logo" src="../../../assets/images/idp/google.png" alt="google" />
|
||||
<div class="text-container">
|
||||
<span class="title">Google</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="item card coming-soon" matRipple>
|
||||
<span class="state coming-soon-label">{{ 'ACTIONS.COMINGSOON' | translate }}</span>
|
||||
<img class="idp-logo" src="../../../assets/images/idp/ms.svg" alt="microsoft" />
|
||||
<div class="text-container">
|
||||
<span class="title">Microsoft</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item card coming-soon" matRipple>
|
||||
<span class="state coming-soon-label">{{ 'ACTIONS.COMINGSOON' | translate }}</span>
|
||||
<img class="idp-logo dark" src="../../../assets/images/idp/github-dark.svg" alt="GitHub" />
|
||||
<img class="idp-logo light" src="../../../assets/images/idp/github.svg" alt="GitHub" />
|
||||
|
||||
<div class="text-container">
|
||||
<span class="title">GitHub</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item card coming-soon" matRipple>
|
||||
<span class="state coming-soon-label">{{ 'ACTIONS.COMINGSOON' | translate }}</span>
|
||||
<img class="idp-logo" src="../../../assets/images/idp/gitlab.svg" alt="GitLab" />
|
||||
<div class="text-container">
|
||||
<span class="title">GitLab</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['/instance', 'provider', 'oidc', 'create']
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['/org', 'provider', 'oidc', 'create']
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="idp-icon">
|
||||
<mat-icon class="icon" svgIcon="mdi_openid" alt="openid" />
|
||||
</div>
|
||||
<div class="text-container">
|
||||
<span class="title">Generic OIDC</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['/instance', 'provider', 'jwt', 'create']
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['/org', 'provider', 'jwt', 'create']
|
||||
: []
|
||||
"
|
||||
>
|
||||
<div class="idp-icon">
|
||||
<mat-icon class="icon" svgIcon="mdi_jwt" alt="jwt" />
|
||||
</div>
|
||||
<div class="text-container">
|
||||
<span class="title">Generic JWT</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,109 @@
|
||||
.cnsl-idp-table-wrapper {
|
||||
display: block;
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@mixin idp-settings-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat.get-color-from-palette($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$background: map-get($theme, background);
|
||||
$foreground: map-get($theme, foreground);
|
||||
|
||||
.cnsl-idp-table-wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.new-idp-wrapper {
|
||||
display: grid;
|
||||
row-gap: 1.5rem;
|
||||
column-gap: 1.5rem;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@media only screen and (min-width: 700px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1000px) {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1300px) {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
padding-top: 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
padding-left: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
box-sizing: border-box;
|
||||
transition: box-shadow 0.1s ease-in;
|
||||
align-items: center;
|
||||
color: map-get($foreground, text);
|
||||
|
||||
.coming-soon-label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 1rem;
|
||||
transform: translateY(-50%);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.idp-logo {
|
||||
margin-right: 1rem;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
|
||||
&.dark {
|
||||
display: if($is-dark-theme, block, none);
|
||||
}
|
||||
|
||||
&.light {
|
||||
display: if($is-dark-theme, none, block);
|
||||
}
|
||||
}
|
||||
|
||||
.idp-icon {
|
||||
margin-right: 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
|
||||
.icon {
|
||||
font-size: 2.25rem;
|
||||
height: 2.25rem;
|
||||
width: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.text-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
}
|
||||
}
|
||||
|
||||
&.coming-soon {
|
||||
filter: grayscale(1);
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ export class IdpSettingsComponent implements OnInit {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public createGoogle() {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { IdpTableModule } from '../../idp-table/idp-table.module';
|
||||
@@ -9,7 +13,17 @@ import { IdpSettingsComponent } from './idp-settings.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [IdpSettingsComponent],
|
||||
imports: [CommonModule, CardModule, IdpTableModule, MatProgressSpinnerModule, TranslateModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatLegacyButtonModule,
|
||||
CardModule,
|
||||
MatIconModule,
|
||||
IdpTableModule,
|
||||
RouterModule,
|
||||
HasRolePipeModule,
|
||||
MatProgressSpinnerModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [IdpSettingsComponent],
|
||||
})
|
||||
export class IdpSettingsModule {}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<form [formGroup]="form" class="option-form">
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="checkbox-desc">{{ 'IDP.OPTIONS.ISAUTOCREATION_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="isAutoCreation">{{ 'IDP.OPTIONS.ISAUTOCREATION' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="checkbox-desc">{{ 'IDP.OPTIONS.ISAUTOUPDATE_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="isAutoUpdate">{{ 'IDP.OPTIONS.ISAUTOUPDATE' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="checkbox-desc">{{ 'IDP.OPTIONS.ISCREATIONALLOWED_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="isCreationAllowed">{{ 'IDP.OPTIONS.ISCREATIONALLOWED' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
<cnsl-info-section class="auto-reg-info">
|
||||
<div>
|
||||
<p class="checkbox-desc">{{ 'IDP.OPTIONS.ISLINKINGALLOWED_DESC' | translate }}</p>
|
||||
<mat-checkbox formControlName="isLinkingAllowed">{{ 'IDP.OPTIONS.ISLINKINGALLOWED' | translate }}</mat-checkbox>
|
||||
</div>
|
||||
</cnsl-info-section>
|
||||
</form>
|
||||
@@ -0,0 +1,11 @@
|
||||
.option-form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
max-width: 400px;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
.checkbox-desc {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProviderOptionsComponent } from './provider-options.component';
|
||||
|
||||
describe('ProviderOptionsComponent', () => {
|
||||
let component: ProviderOptionsComponent;
|
||||
let fixture: ComponentFixture<ProviderOptionsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ProviderOptionsComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ProviderOptionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
import { Options } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-options',
|
||||
templateUrl: './provider-options.component.html',
|
||||
styleUrls: ['./provider-options.component.scss'],
|
||||
})
|
||||
export class ProviderOptionsComponent implements OnChanges, OnDestroy {
|
||||
@Input() public initialOptions?: Options.AsObject;
|
||||
@Output() public optionsChanged: EventEmitter<Options> = new EventEmitter<Options>();
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
public form: FormGroup = new FormGroup({
|
||||
isAutoCreation: new FormControl(false, []),
|
||||
isAutoUpdate: new FormControl(false, []),
|
||||
isCreationAllowed: new FormControl(true, []),
|
||||
isLinkingAllowed: new FormControl(true, []),
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||
if (value) {
|
||||
const opt = new Options();
|
||||
opt.setIsAutoCreation(value.isAutoCreation);
|
||||
opt.setIsAutoUpdate(value.isAutoUpdate);
|
||||
opt.setIsCreationAllowed(value.isCreationAllowed);
|
||||
opt.setIsLinkingAllowed(value.isLinkingAllowed);
|
||||
this.optionsChanged.emit(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
if (this.initialOptions) {
|
||||
this.form.patchValue(this.initialOptions);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||
import { ProviderOptionsComponent } from './provider-options.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProviderOptionsComponent],
|
||||
imports: [CommonModule, MatCheckboxModule, FormsModule, InfoSectionModule, ReactiveFormsModule, TranslateModule],
|
||||
exports: [ProviderOptionsComponent],
|
||||
})
|
||||
export class ProviderOptionsModule {}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { ProviderGoogleComponent } from './provider-google.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ProviderGoogleComponent,
|
||||
data: { animation: 'DetailPage' },
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ProviderGoogleRoutingModule {}
|
||||
@@ -0,0 +1,93 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ id ? ('IDP.DETAIL.TITLE' | translate) : ('IDP.CREATE.TITLE' | translate) }}"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="google-create-content">
|
||||
<div class="title-row">
|
||||
<img class="idp-logo" src="../../../assets/images/idp/google.png" alt="google" />
|
||||
<h1>{{ 'IDP.CREATE.GOOGLE.TITLE' | translate }}</h1>
|
||||
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="desc cnsl-secondary-text">
|
||||
{{ !provider ? ('IDP.CREATE.GOOGLE.DESCRIPTION' | translate) : ('IDP.DETAIL.DESCRIPTION' | translate) }}
|
||||
</p>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="submitForm()">
|
||||
<div class="google-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
|
||||
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showOptional">
|
||||
<div class="idp-scopes">
|
||||
<div class="flex-line">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
<span class="name-hint cnsl-secondary-text" cnslHint>{{ 'IDP.NAMEHINT' | translate }}</span>
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-provider-options
|
||||
[initialOptions]="provider?.config?.options"
|
||||
(optionsChanged)="options = $event"
|
||||
></cnsl-provider-options>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="google-create-actions">
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" type="submit">
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
<span *ngIf="!id">{{ 'ACTIONS.CREATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
||||
@@ -0,0 +1,87 @@
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.google-create-content {
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.idp-logo {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
|
||||
.name-hint {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mat-chip-input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 0.5rem;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.google-content {
|
||||
.desc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.idp-scopes {
|
||||
padding-bottom: 0.5rem;
|
||||
|
||||
.flex-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
max-width: 400px;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scope-add-button {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.google-create-actions {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.optional-h-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProviderGoogleComponent } from './provider-google.component';
|
||||
|
||||
describe('ProviderGoogleComponent', () => {
|
||||
let component: ProviderGoogleComponent;
|
||||
let fixture: ComponentFixture<ProviderGoogleComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderGoogleComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProviderGoogleComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,268 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, Type } from '@angular/core';
|
||||
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { take } from 'rxjs';
|
||||
import {
|
||||
AddGoogleProviderRequest as AdminAddGoogleProviderRequest,
|
||||
GetProviderByIDRequest as AdminGetProviderByIDRequest,
|
||||
UpdateGoogleProviderRequest as AdminUpdateGoogleProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { Options, Provider } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
AddGoogleProviderRequest as MgmtAddGoogleProviderRequest,
|
||||
GetProviderByIDRequest as MgmtGetProviderByIDRequest,
|
||||
UpdateGoogleProviderRequest as MgmtUpdateGoogleProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-google',
|
||||
templateUrl: './provider-google.component.html',
|
||||
styleUrls: ['./provider-google.component.scss'],
|
||||
})
|
||||
export class ProviderGoogleComponent {
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options();
|
||||
public id: string | null = '';
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
|
||||
public form!: FormGroup;
|
||||
|
||||
public loading: boolean = false;
|
||||
|
||||
public provider?: Provider.AsObject;
|
||||
public updateClientSecret: boolean = false;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private _location: Location,
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl('', []),
|
||||
clientId: new FormControl('', [Validators.required]),
|
||||
clientSecret: new FormControl('', [Validators.required]),
|
||||
scopesList: new FormControl(['openid', 'profile', 'email'], []),
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
this.breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
this.breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
if (this.id) {
|
||||
this.clientSecret?.setValidators([]);
|
||||
this.getData(this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getData(id: string): void {
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? new AdminGetProviderByIDRequest()
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.google) {
|
||||
this.form.patchValue(this.provider.config.google);
|
||||
this.name?.setValue(this.provider.name);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public submitForm(): void {
|
||||
this.provider ? this.updateGoogleProvider() : this.addGoogleProvider();
|
||||
}
|
||||
|
||||
public addGoogleProvider(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtAddGoogleProviderRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addGoogleProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminAddGoogleProviderRequest();
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addGoogleProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateGoogleProvider(): void {
|
||||
if (this.provider) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtUpdateGoogleProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
if (this.updateClientSecret) {
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.updateGoogleProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminUpdateGoogleProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
if (this.updateClientSecret) {
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.updateGoogleProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public addScope(event: MatChipInputEvent): void {
|
||||
const input = event.chipInput?.inputElement;
|
||||
const value = event.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (this.scopesList?.value) {
|
||||
this.scopesList.value.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeScope(uri: string): void {
|
||||
if (this.scopesList?.value) {
|
||||
const index = this.scopesList.value.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.scopesList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
public get clientId(): AbstractControl | null {
|
||||
return this.form.get('clientId');
|
||||
}
|
||||
|
||||
public get clientSecret(): AbstractControl | null {
|
||||
return this.form.get('clientSecret');
|
||||
}
|
||||
|
||||
public get scopesList(): AbstractControl | null {
|
||||
return this.form.get('scopesList');
|
||||
}
|
||||
}
|
||||
+19
-27
@@ -5,47 +5,39 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
|
||||
import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyMenuModule as MatMenuModule } from '@angular/material/legacy-menu';
|
||||
import { MatLegacyProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-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 { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { CardModule } from '../card/card.module';
|
||||
import { InfoRowModule } from '../info-row/info-row.module';
|
||||
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||
import { TopViewModule } from '../top-view/top-view.module';
|
||||
import { WarnDialogModule } from '../warn-dialog/warn-dialog.module';
|
||||
import { IdpRoutingModule } from './idp-routing.module';
|
||||
import { IdpComponent } from './idp.component';
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { CreateLayoutModule } from '../../create-layout/create-layout.module';
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { ProviderOptionsModule } from '../../provider-options/provider-options.module';
|
||||
import { ProviderGoogleRoutingModule } from './provider-google-routing.module';
|
||||
import { ProviderGoogleComponent } from './provider-google.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [IdpComponent],
|
||||
declarations: [ProviderGoogleComponent],
|
||||
imports: [
|
||||
ProviderGoogleRoutingModule,
|
||||
CommonModule,
|
||||
IdpRoutingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CreateLayoutModule,
|
||||
InfoSectionModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
WarnDialogModule,
|
||||
MatIconModule,
|
||||
InfoSectionModule,
|
||||
MatMenuModule,
|
||||
TopViewModule,
|
||||
MatTooltipModule,
|
||||
MatSelectModule,
|
||||
CardModule,
|
||||
TranslateModule,
|
||||
MatCheckboxModule,
|
||||
InfoRowModule,
|
||||
MatIconModule,
|
||||
MatChipsModule,
|
||||
HasRoleModule,
|
||||
HasRolePipeModule,
|
||||
DetailLayoutModule,
|
||||
CardModule,
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
ProviderOptionsModule,
|
||||
MatLegacyProgressSpinnerModule,
|
||||
],
|
||||
})
|
||||
export default class IdpModule {}
|
||||
export default class ProviderGoogleModule {}
|
||||
+3
-4
@@ -1,12 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { IdpComponent } from './idp.component';
|
||||
import { ProviderJWTComponent } from './provider-jwt.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: IdpComponent,
|
||||
component: ProviderJWTComponent,
|
||||
data: { animation: 'DetailPage' },
|
||||
},
|
||||
];
|
||||
@@ -15,4 +14,4 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class IdpRoutingModule {}
|
||||
export class ProviderJWTCreateRoutingModule {}
|
||||
@@ -0,0 +1,60 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ id ? ('IDP.DETAIL.TITLE' | translate) : ('IDP.CREATE.TITLE' | translate) }}"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="jwt-create-content">
|
||||
<div class="title-row">
|
||||
<mat-icon class="idp-logo" svgIcon="mdi_jwt" alt="jwt" />
|
||||
<h1>{{ 'IDP.CREATE.JWT.TITLE' | translate }}</h1>
|
||||
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.CREATE.JWT.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="submitForm()">
|
||||
<div class="jwt-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.HEADERNAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="headerName" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="jwtEndpoint" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="keysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
|
||||
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showOptional">
|
||||
<cnsl-provider-options
|
||||
[initialOptions]="provider?.config?.options"
|
||||
(optionsChanged)="options = $event"
|
||||
></cnsl-provider-options>
|
||||
</div>
|
||||
|
||||
<div class="jwt-create-actions">
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" type="submit">
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
<span *ngIf="!id">{{ 'ACTIONS.CREATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
||||
+25
-23
@@ -2,25 +2,23 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.add-line-btn {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.jwt-create-content {
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.first-step-actions {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.idp-logo {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.auto-reg-info {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
|
||||
.auto-reg-desc {
|
||||
margin: 0 0 1rem 0;
|
||||
h1 {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.idp-create-content {
|
||||
.formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
@@ -40,7 +38,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.idp-content {
|
||||
.jwt-content {
|
||||
.desc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -67,17 +65,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
.idp-create-actions {
|
||||
.jwt-create-actions {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-stroked-button] {
|
||||
border-radius: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.optional-h-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpComponent } from './idp.component';
|
||||
import { ProviderJWTComponent } from './provider-jwt.component';
|
||||
|
||||
describe('IdComponent', () => {
|
||||
let component: IdpComponent;
|
||||
let fixture: ComponentFixture<IdpComponent>;
|
||||
describe('ProviderJWTComponent', () => {
|
||||
let component: ProviderJWTComponent;
|
||||
let fixture: ComponentFixture<ProviderJWTComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpComponent],
|
||||
declarations: [ProviderJWTComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(IdpComponent);
|
||||
fixture = TestBed.createComponent(ProviderJWTComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,245 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { take } from 'rxjs/operators';
|
||||
import {
|
||||
AddJWTProviderRequest as AdminAddJWTProviderRequest,
|
||||
GetProviderByIDRequest as AdminGetProviderByIDRequest,
|
||||
UpdateJWTProviderRequest as AdminUpdateJWTProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { Options, Provider } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
AddJWTProviderRequest as MgmtAddJWTProviderRequest,
|
||||
GetProviderByIDRequest as MgmtGetProviderByIDRequest,
|
||||
UpdateJWTProviderRequest as MgmtUpdateJWTProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-jwt',
|
||||
templateUrl: './provider-jwt.component.html',
|
||||
styleUrls: ['./provider-jwt.component.scss'],
|
||||
})
|
||||
export class ProviderJWTComponent {
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options();
|
||||
|
||||
public id: string | null = '';
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
|
||||
public form!: UntypedFormGroup;
|
||||
public loading: boolean = false;
|
||||
|
||||
public provider?: Provider.AsObject;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private _location: Location,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
console.log(data.serviceType);
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
if (this.id) {
|
||||
this.getData(this.id);
|
||||
}
|
||||
});
|
||||
|
||||
this.form = new UntypedFormGroup({
|
||||
name: new UntypedFormControl('', [Validators.required]),
|
||||
headerName: new UntypedFormControl('', [Validators.required]),
|
||||
issuer: new UntypedFormControl('', [Validators.required]),
|
||||
jwtEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
keysEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
});
|
||||
}
|
||||
|
||||
private getData(id: string): void {
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? new AdminGetProviderByIDRequest()
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.jwt) {
|
||||
this.form.patchValue(this.provider.config.jwt);
|
||||
this.name?.setValue(this.provider.name);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public submitForm(): void {
|
||||
this.provider ? this.updateJWTProvider() : this.addJWTProvider();
|
||||
}
|
||||
|
||||
public addJWTProvider(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtAddJWTProviderRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addJWTProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminAddJWTProviderRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addJWTProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateJWTProvider(): void {
|
||||
if (this.provider) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtUpdateJWTProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.updateJWTProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminUpdateJWTProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setHeaderName(this.headerName?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.updateJWTProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
public get headerName(): AbstractControl | null {
|
||||
return this.form.get('headerName');
|
||||
}
|
||||
|
||||
public get issuer(): AbstractControl | null {
|
||||
return this.form.get('issuer');
|
||||
}
|
||||
|
||||
public get jwtEndpoint(): AbstractControl | null {
|
||||
return this.form.get('jwtEndpoint');
|
||||
}
|
||||
|
||||
public get keysEndpoint(): AbstractControl | null {
|
||||
return this.form.get('keysEndpoint');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
|
||||
import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { CreateLayoutModule } from '../../create-layout/create-layout.module';
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { ProviderOptionsModule } from '../../provider-options/provider-options.module';
|
||||
import { ProviderJWTCreateRoutingModule } from './provider-jwt-routing.module';
|
||||
import { ProviderJWTComponent } from './provider-jwt.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProviderJWTComponent],
|
||||
imports: [
|
||||
ProviderJWTCreateRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CreateLayoutModule,
|
||||
InfoSectionModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
MatIconModule,
|
||||
MatChipsModule,
|
||||
CardModule,
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
ProviderOptionsModule,
|
||||
MatLegacyProgressSpinnerModule,
|
||||
],
|
||||
})
|
||||
export default class ProviderJWTModule {}
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { IdpCreateComponent } from './idp-create.component';
|
||||
import { ProviderOIDCComponent } from './provider-oidc.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: IdpCreateComponent,
|
||||
component: ProviderOIDCComponent,
|
||||
data: { animation: 'DetailPage' },
|
||||
},
|
||||
];
|
||||
@@ -15,4 +15,4 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class IdpCreateRoutingModule {}
|
||||
export class ProviderOIDCRoutingModule {}
|
||||
@@ -0,0 +1,96 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ id ? ('IDP.DETAIL.TITLE' | translate) : ('IDP.CREATE.TITLE' | translate) }}"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="oidc-create-content">
|
||||
<div class="title-row">
|
||||
<mat-icon class="idp-logo" svgIcon="mdi_openid" alt="openid" />
|
||||
<h1>{{ 'IDP.CREATE.OIDC.TITLE' | translate }}</h1>
|
||||
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.CREATE.OIDC.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="oidcFormGroup" (ngSubmit)="submitForm()">
|
||||
<div class="oidc-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.ISSUER' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="issuer" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="oidc-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
|
||||
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showOptional">
|
||||
<div class="idp-scopes">
|
||||
<div class="flex-line">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-provider-options
|
||||
[initialOptions]="provider?.config?.options"
|
||||
(optionsChanged)="options = $event"
|
||||
></cnsl-provider-options>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oidc-create-actions">
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="oidcFormGroup.invalid" type="submit">
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
<span *ngIf="!id">{{ 'ACTIONS.CREATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
||||
@@ -0,0 +1,84 @@
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.oidc-create-content {
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.idp-logo {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
|
||||
.mat-chip-input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 0.5rem;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.oidc-content {
|
||||
.desc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.idp-scopes {
|
||||
padding-bottom: 0.5rem;
|
||||
|
||||
.flex-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
max-width: 400px;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scope-add-button {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.oidc-create-actions {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.optional-h-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpCreateComponent } from './idp-create.component';
|
||||
import { ProviderOIDCComponent } from './provider-oidc.component';
|
||||
|
||||
describe('IdpCreateComponent', () => {
|
||||
let component: IdpCreateComponent;
|
||||
let fixture: ComponentFixture<IdpCreateComponent>;
|
||||
describe('ProviderOIDCComponent', () => {
|
||||
let component: ProviderOIDCComponent;
|
||||
let fixture: ComponentFixture<ProviderOIDCComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpCreateComponent],
|
||||
declarations: [ProviderOIDCComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(IdpCreateComponent);
|
||||
fixture = TestBed.createComponent(ProviderOIDCComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
@@ -0,0 +1,267 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { take } from 'rxjs';
|
||||
import {
|
||||
AddGenericOIDCProviderRequest as AdminAddGenericOIDCProviderRequest,
|
||||
GetProviderByIDRequest as AdminGetProviderByIDRequest,
|
||||
UpdateGenericOIDCProviderRequest as AdminUpdateGenericOIDCProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { Options, Provider } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
AddGenericOIDCProviderRequest as MgmtAddGenericOIDCProviderRequest,
|
||||
GetProviderByIDRequest as MgmtGetProviderByIDRequest,
|
||||
UpdateGenericOIDCProviderRequest as MgmtUpdateGenericOIDCProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-oidc',
|
||||
templateUrl: './provider-oidc.component.html',
|
||||
styleUrls: ['./provider-oidc.component.scss'],
|
||||
})
|
||||
export class ProviderOIDCComponent {
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options();
|
||||
|
||||
public id: string | null = '';
|
||||
public updateClientSecret: boolean = false;
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
public oidcFormGroup!: UntypedFormGroup;
|
||||
|
||||
public loading: boolean = false;
|
||||
|
||||
public provider?: Provider.AsObject;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private _location: Location,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.oidcFormGroup = new UntypedFormGroup({
|
||||
name: new UntypedFormControl('', [Validators.required]),
|
||||
clientId: new UntypedFormControl('', [Validators.required]),
|
||||
clientSecret: new UntypedFormControl('', [Validators.required]),
|
||||
issuer: new UntypedFormControl('', [Validators.required]),
|
||||
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
if (this.id) {
|
||||
this.clientSecret?.setValidators([]);
|
||||
this.getData(this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getData(id: string): void {
|
||||
this.loading = true;
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? new AdminGetProviderByIDRequest()
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.oidc) {
|
||||
this.oidcFormGroup.patchValue(this.provider.config.oidc);
|
||||
this.name?.setValue(this.provider.name);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public submitForm(): void {
|
||||
this.provider ? this.updateGenericOIDCProvider() : this.addGenericOIDCProvider();
|
||||
}
|
||||
|
||||
public addGenericOIDCProvider(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtAddGenericOIDCProviderRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addGenericOIDCProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminAddGenericOIDCProviderRequest();
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addGenericOIDCProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateGenericOIDCProvider(): void {
|
||||
if (this.provider) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtUpdateGenericOIDCProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.updateGenericOIDCProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminUpdateGenericOIDCProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.updateGenericOIDCProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public addScope(event: MatChipInputEvent): void {
|
||||
const input = event.chipInput?.inputElement;
|
||||
const value = event.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (this.scopesList?.value) {
|
||||
this.scopesList.value.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeScope(uri: string): void {
|
||||
if (this.scopesList?.value) {
|
||||
const index = this.scopesList.value.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.scopesList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('name');
|
||||
}
|
||||
|
||||
public get clientId(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('clientId');
|
||||
}
|
||||
|
||||
public get clientSecret(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('clientSecret');
|
||||
}
|
||||
|
||||
public get issuer(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('issuer');
|
||||
}
|
||||
|
||||
public get scopesList(): AbstractControl | null {
|
||||
return this.oidcFormGroup.get('scopesList');
|
||||
}
|
||||
}
|
||||
+12
-11
@@ -5,23 +5,23 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
|
||||
import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyProgressBarModule as MatProgressBarModule } from '@angular/material/legacy-progress-bar';
|
||||
import { MatLegacyProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { CardModule } from '../card/card.module';
|
||||
import { CreateLayoutModule } from '../create-layout/create-layout.module';
|
||||
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||
import { IdpCreateRoutingModule } from './idp-create-routing.module';
|
||||
import { IdpCreateComponent } from './idp-create.component';
|
||||
import { IdpTypeRadioComponent } from './idp-type-radio/idp-type-radio.component';
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { CreateLayoutModule } from '../../create-layout/create-layout.module';
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { ProviderOptionsModule } from '../../provider-options/provider-options.module';
|
||||
import { ProviderOIDCRoutingModule } from './provider-oidc-routing.module';
|
||||
import { ProviderOIDCComponent } from './provider-oidc.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [IdpCreateComponent, IdpTypeRadioComponent],
|
||||
declarations: [ProviderOIDCComponent],
|
||||
imports: [
|
||||
IdpCreateRoutingModule,
|
||||
ProviderOIDCRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
@@ -36,7 +36,8 @@ import { IdpTypeRadioComponent } from './idp-type-radio/idp-type-radio.component
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
MatProgressBarModule,
|
||||
ProviderOptionsModule,
|
||||
MatLegacyProgressSpinnerModule,
|
||||
],
|
||||
})
|
||||
export default class IdpCreateModule {}
|
||||
export default class ProviderOIDCModule {}
|
||||
@@ -24,25 +24,51 @@ const routes: Routes = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'idp',
|
||||
path: 'provider',
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.write'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/idp-create/idp-create.module'),
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.write'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
path: 'oidc',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oidc/provider-oidc.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oidc/provider-oidc.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/idp/idp.module'),
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['iam.idp.read'],
|
||||
serviceType: PolicyComponentServiceType.ADMIN,
|
||||
},
|
||||
path: 'jwt',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-jwt/provider-jwt.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-jwt/provider-jwt.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'google',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-google/provider-google.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-google/provider-google.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,38 +1,65 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AuthGuard } from 'src/app/guards/auth.guard';
|
||||
import { RoleGuard } from 'src/app/guards/role.guard';
|
||||
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
|
||||
import { OrgDetailComponent } from './org-detail/org-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'idp',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/idp-create/idp-create.module'),
|
||||
canActivate: [RoleGuard],
|
||||
data: {
|
||||
roles: ['org.idp.write'],
|
||||
serviceType: PolicyComponentServiceType.MGMT,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/idp/idp.module'),
|
||||
canActivate: [RoleGuard],
|
||||
data: {
|
||||
roles: ['org.idp.read'],
|
||||
serviceType: PolicyComponentServiceType.MGMT,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'members',
|
||||
loadChildren: () => import('./org-members/org-members.module'),
|
||||
},
|
||||
{
|
||||
path: 'provider',
|
||||
canActivate: [AuthGuard, RoleGuard],
|
||||
data: {
|
||||
roles: ['org.idp.write'],
|
||||
serviceType: PolicyComponentServiceType.MGMT,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'oidc',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oidc/provider-oidc.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oidc/provider-oidc.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'jwt',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-jwt/provider-jwt.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-jwt/provider-jwt.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'google',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-google/provider-google.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-google/provider-google.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: OrgDetailComponent,
|
||||
|
||||
@@ -8,18 +8,20 @@ import {
|
||||
ActivateSMSProviderResponse,
|
||||
AddCustomDomainPolicyRequest,
|
||||
AddCustomOrgIAMPolicyResponse,
|
||||
AddGenericOIDCProviderRequest,
|
||||
AddGenericOIDCProviderResponse,
|
||||
AddGoogleProviderRequest,
|
||||
AddGoogleProviderResponse,
|
||||
AddIAMMemberRequest,
|
||||
AddIAMMemberResponse,
|
||||
AddIDPToLoginPolicyRequest,
|
||||
AddIDPToLoginPolicyResponse,
|
||||
AddJWTIDPRequest,
|
||||
AddJWTIDPResponse,
|
||||
AddJWTProviderRequest,
|
||||
AddJWTProviderResponse,
|
||||
AddMultiFactorToLoginPolicyRequest,
|
||||
AddMultiFactorToLoginPolicyResponse,
|
||||
AddNotificationPolicyRequest,
|
||||
AddNotificationPolicyResponse,
|
||||
AddOIDCIDPRequest,
|
||||
AddOIDCIDPResponse,
|
||||
AddOIDCSettingsRequest,
|
||||
AddOIDCSettingsResponse,
|
||||
AddSecondFactorToLoginPolicyRequest,
|
||||
@@ -32,6 +34,8 @@ import {
|
||||
DeactivateIDPResponse,
|
||||
DeactivateSMSProviderRequest,
|
||||
DeactivateSMSProviderResponse,
|
||||
DeleteProviderRequest,
|
||||
DeleteProviderResponse,
|
||||
GetCustomDomainClaimedMessageTextRequest,
|
||||
GetCustomDomainClaimedMessageTextResponse,
|
||||
GetCustomDomainPolicyRequest,
|
||||
@@ -72,8 +76,6 @@ import {
|
||||
GetDomainPolicyResponse,
|
||||
GetFileSystemNotificationProviderRequest,
|
||||
GetFileSystemNotificationProviderResponse,
|
||||
GetIDPByIDRequest,
|
||||
GetIDPByIDResponse,
|
||||
GetLabelPolicyRequest,
|
||||
GetLabelPolicyResponse,
|
||||
GetLockoutPolicyRequest,
|
||||
@@ -96,6 +98,8 @@ import {
|
||||
GetPreviewLabelPolicyResponse,
|
||||
GetPrivacyPolicyRequest,
|
||||
GetPrivacyPolicyResponse,
|
||||
GetProviderByIDRequest,
|
||||
GetProviderByIDResponse,
|
||||
GetSecretGeneratorRequest,
|
||||
GetSecretGeneratorResponse,
|
||||
GetSecurityPolicyRequest,
|
||||
@@ -106,7 +110,6 @@ import {
|
||||
GetSMTPConfigResponse,
|
||||
GetSupportedLanguagesRequest,
|
||||
GetSupportedLanguagesResponse,
|
||||
IDPQuery,
|
||||
ListAggregateTypesRequest,
|
||||
ListAggregateTypesResponse,
|
||||
ListEventsRequest,
|
||||
@@ -119,14 +122,14 @@ import {
|
||||
ListIAMMemberRolesResponse,
|
||||
ListIAMMembersRequest,
|
||||
ListIAMMembersResponse,
|
||||
ListIDPsRequest,
|
||||
ListIDPsResponse,
|
||||
ListLoginPolicyIDPsRequest,
|
||||
ListLoginPolicyIDPsResponse,
|
||||
ListLoginPolicyMultiFactorsRequest,
|
||||
ListLoginPolicyMultiFactorsResponse,
|
||||
ListLoginPolicySecondFactorsRequest,
|
||||
ListLoginPolicySecondFactorsResponse,
|
||||
ListProvidersRequest,
|
||||
ListProvidersResponse,
|
||||
ListSecretGeneratorsRequest,
|
||||
ListSecretGeneratorsResponse,
|
||||
ListSMSProvidersRequest,
|
||||
@@ -191,14 +194,14 @@ import {
|
||||
UpdateCustomDomainPolicyResponse,
|
||||
UpdateDomainPolicyRequest,
|
||||
UpdateDomainPolicyResponse,
|
||||
UpdateGenericOIDCProviderRequest,
|
||||
UpdateGenericOIDCProviderResponse,
|
||||
UpdateGoogleProviderRequest,
|
||||
UpdateGoogleProviderResponse,
|
||||
UpdateIAMMemberRequest,
|
||||
UpdateIAMMemberResponse,
|
||||
UpdateIDPJWTConfigRequest,
|
||||
UpdateIDPJWTConfigResponse,
|
||||
UpdateIDPOIDCConfigRequest,
|
||||
UpdateIDPOIDCConfigResponse,
|
||||
UpdateIDPRequest,
|
||||
UpdateIDPResponse,
|
||||
UpdateJWTProviderRequest,
|
||||
UpdateJWTProviderResponse,
|
||||
UpdateLabelPolicyRequest,
|
||||
UpdateLabelPolicyResponse,
|
||||
UpdateLockoutPolicyRequest,
|
||||
@@ -871,41 +874,6 @@ export class AdminService {
|
||||
return this.grpcService.admin.listLoginPolicyIDPs(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listIDPs(limit?: number, offset?: number, queriesList?: IDPQuery[]): Promise<ListIDPsResponse.AsObject> {
|
||||
const req = new ListIDPsRequest();
|
||||
const query = new ListQuery();
|
||||
|
||||
if (limit) {
|
||||
query.setLimit(limit);
|
||||
}
|
||||
if (offset) {
|
||||
query.setOffset(offset);
|
||||
}
|
||||
if (queriesList) {
|
||||
req.setQueriesList(queriesList);
|
||||
}
|
||||
req.setQuery(query);
|
||||
return this.grpcService.admin.listIDPs(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getIDPByID(id: string): Promise<GetIDPByIDResponse.AsObject> {
|
||||
const req = new GetIDPByIDRequest();
|
||||
req.setId(id);
|
||||
return this.grpcService.admin.getIDPByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateIDP(req: UpdateIDPRequest): Promise<UpdateIDPResponse.AsObject> {
|
||||
return this.grpcService.admin.updateIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addOIDCIDP(req: AddOIDCIDPRequest): Promise<AddOIDCIDPResponse.AsObject> {
|
||||
return this.grpcService.admin.addOIDCIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateIDPOIDCConfig(req: UpdateIDPOIDCConfigRequest): Promise<UpdateIDPOIDCConfigResponse.AsObject> {
|
||||
return this.grpcService.admin.updateIDPOIDCConfig(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public removeIDP(id: string): Promise<RemoveIDPResponse.AsObject> {
|
||||
const req = new RemoveIDPRequest();
|
||||
req.setIdpId(id);
|
||||
@@ -924,12 +892,44 @@ export class AdminService {
|
||||
return this.grpcService.admin.reactivateIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addJWTIDP(req: AddJWTIDPRequest): Promise<AddJWTIDPResponse.AsObject> {
|
||||
return this.grpcService.admin.addJWTIDP(req, null).then((resp) => resp.toObject());
|
||||
// idp templates
|
||||
|
||||
public addGoogleProvider(req: AddGoogleProviderRequest): Promise<AddGoogleProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addGoogleProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateIDPJWTConfig(req: UpdateIDPJWTConfigRequest): Promise<UpdateIDPJWTConfigResponse.AsObject> {
|
||||
return this.grpcService.admin.updateIDPJWTConfig(req, null).then((resp) => resp.toObject());
|
||||
public updateGoogleProvider(req: UpdateGoogleProviderRequest): Promise<UpdateGoogleProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.updateGoogleProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGenericOIDCProvider(req: AddGenericOIDCProviderRequest): Promise<AddGenericOIDCProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateGenericOIDCProvider(
|
||||
req: UpdateGenericOIDCProviderRequest,
|
||||
): Promise<UpdateGenericOIDCProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.updateGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addJWTProvider(req: AddJWTProviderRequest): Promise<AddJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateJWTProvider(req: UpdateJWTProviderRequest): Promise<UpdateJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.updateJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public deleteProvider(req: DeleteProviderRequest): Promise<DeleteProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.deleteProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listProviders(req: ListProvidersRequest): Promise<ListProvidersResponse.AsObject> {
|
||||
return this.grpcService.admin.listProviders(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getProviderByID(req: GetProviderByIDRequest): Promise<GetProviderByIDResponse.AsObject> {
|
||||
return this.grpcService.admin.getProviderByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listIAMMembers(
|
||||
|
||||
@@ -3,7 +3,6 @@ import { SortDirection } from '@angular/material/sort';
|
||||
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
|
||||
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { AppQuery } from '../proto/generated/zitadel/app_pb';
|
||||
import { KeyType } from '../proto/generated/zitadel/auth_n_key_pb';
|
||||
import { ChangeQuery } from '../proto/generated/zitadel/change_pb';
|
||||
@@ -30,10 +29,16 @@ import {
|
||||
AddCustomPasswordComplexityPolicyResponse,
|
||||
AddCustomPrivacyPolicyRequest,
|
||||
AddCustomPrivacyPolicyResponse,
|
||||
AddGenericOIDCProviderRequest,
|
||||
AddGenericOIDCProviderResponse,
|
||||
AddGoogleProviderRequest,
|
||||
AddGoogleProviderResponse,
|
||||
AddHumanUserRequest,
|
||||
AddHumanUserResponse,
|
||||
AddIDPToLoginPolicyRequest,
|
||||
AddIDPToLoginPolicyResponse,
|
||||
AddJWTProviderRequest,
|
||||
AddJWTProviderResponse,
|
||||
AddMachineKeyRequest,
|
||||
AddMachineKeyResponse,
|
||||
AddMachineUserRequest,
|
||||
@@ -44,12 +49,8 @@ import {
|
||||
AddOIDCAppResponse,
|
||||
AddOrgDomainRequest,
|
||||
AddOrgDomainResponse,
|
||||
AddOrgJWTIDPRequest,
|
||||
AddOrgJWTIDPResponse,
|
||||
AddOrgMemberRequest,
|
||||
AddOrgMemberResponse,
|
||||
AddOrgOIDCIDPRequest,
|
||||
AddOrgOIDCIDPResponse,
|
||||
AddOrgRequest,
|
||||
AddOrgResponse,
|
||||
AddPersonalAccessTokenRequest,
|
||||
@@ -96,6 +97,8 @@ import {
|
||||
DeactivateUserResponse,
|
||||
DeleteActionRequest,
|
||||
DeleteActionResponse,
|
||||
DeleteProviderRequest,
|
||||
DeleteProviderResponse,
|
||||
GenerateMachineSecretRequest,
|
||||
GenerateMachineSecretResponse,
|
||||
GenerateOrgDomainValidationRequest,
|
||||
@@ -168,8 +171,6 @@ import {
|
||||
GetOIDCInformationResponse,
|
||||
GetOrgByDomainGlobalRequest,
|
||||
GetOrgByDomainGlobalResponse,
|
||||
GetOrgIDPByIDRequest,
|
||||
GetOrgIDPByIDResponse,
|
||||
GetPasswordAgePolicyRequest,
|
||||
GetPasswordAgePolicyResponse,
|
||||
GetPasswordComplexityPolicyRequest,
|
||||
@@ -182,6 +183,8 @@ import {
|
||||
GetProjectByIDResponse,
|
||||
GetProjectGrantByIDRequest,
|
||||
GetProjectGrantByIDResponse,
|
||||
GetProviderByIDRequest,
|
||||
GetProviderByIDResponse,
|
||||
GetSupportedLanguagesRequest,
|
||||
GetSupportedLanguagesResponse,
|
||||
GetUserByIDRequest,
|
||||
@@ -192,7 +195,6 @@ import {
|
||||
GetUserGrantByIDResponse,
|
||||
GetUserMetadataRequest,
|
||||
GetUserMetadataResponse,
|
||||
IDPQuery,
|
||||
ListActionsRequest,
|
||||
ListActionsResponse,
|
||||
ListAppChangesRequest,
|
||||
@@ -226,8 +228,6 @@ import {
|
||||
ListOrgChangesResponse,
|
||||
ListOrgDomainsRequest,
|
||||
ListOrgDomainsResponse,
|
||||
ListOrgIDPsRequest,
|
||||
ListOrgIDPsResponse,
|
||||
ListOrgMemberRolesRequest,
|
||||
ListOrgMemberRolesResponse,
|
||||
ListOrgMembersRequest,
|
||||
@@ -254,6 +254,8 @@ import {
|
||||
ListProjectRolesResponse,
|
||||
ListProjectsRequest,
|
||||
ListProjectsResponse,
|
||||
ListProvidersRequest,
|
||||
ListProvidersResponse,
|
||||
ListUserChangesRequest,
|
||||
ListUserChangesResponse,
|
||||
ListUserGrantRequest,
|
||||
@@ -425,22 +427,22 @@ import {
|
||||
UpdateCustomPasswordComplexityPolicyResponse,
|
||||
UpdateCustomPrivacyPolicyRequest,
|
||||
UpdateCustomPrivacyPolicyResponse,
|
||||
UpdateGenericOIDCProviderRequest,
|
||||
UpdateGenericOIDCProviderResponse,
|
||||
UpdateGoogleProviderRequest,
|
||||
UpdateGoogleProviderResponse,
|
||||
UpdateHumanEmailRequest,
|
||||
UpdateHumanEmailResponse,
|
||||
UpdateHumanPhoneRequest,
|
||||
UpdateHumanPhoneResponse,
|
||||
UpdateHumanProfileRequest,
|
||||
UpdateHumanProfileResponse,
|
||||
UpdateJWTProviderRequest,
|
||||
UpdateJWTProviderResponse,
|
||||
UpdateMachineRequest,
|
||||
UpdateMachineResponse,
|
||||
UpdateOIDCAppConfigRequest,
|
||||
UpdateOIDCAppConfigResponse,
|
||||
UpdateOrgIDPJWTConfigRequest,
|
||||
UpdateOrgIDPJWTConfigResponse,
|
||||
UpdateOrgIDPOIDCConfigRequest,
|
||||
UpdateOrgIDPOIDCConfigResponse,
|
||||
UpdateOrgIDPRequest,
|
||||
UpdateOrgIDPResponse,
|
||||
UpdateOrgMemberRequest,
|
||||
UpdateOrgMemberResponse,
|
||||
UpdateOrgRequest,
|
||||
@@ -692,23 +694,6 @@ export class ManagementService {
|
||||
.then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listOrgIDPs(limit?: number, offset?: number, queryList?: IDPQuery[]): Promise<ListOrgIDPsResponse.AsObject> {
|
||||
const req = new ListOrgIDPsRequest();
|
||||
const query = new ListQuery();
|
||||
|
||||
if (limit) {
|
||||
query.setLimit(limit);
|
||||
}
|
||||
if (offset) {
|
||||
query.setOffset(offset);
|
||||
}
|
||||
req.setQuery(query);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return this.grpcService.mgmt.listOrgIDPs(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateUserName(userId: string, username: string): Promise<UpdateUserNameResponse.AsObject> {
|
||||
const req = new UpdateUserNameRequest();
|
||||
req.setUserId(userId);
|
||||
@@ -848,24 +833,6 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.listLoginPolicyIDPs(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getOrgIDPByID(id: string): Promise<GetOrgIDPByIDResponse.AsObject> {
|
||||
const req = new GetOrgIDPByIDRequest();
|
||||
req.setId(id);
|
||||
return this.grpcService.mgmt.getOrgIDPByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateOrgIDP(req: UpdateOrgIDPRequest): Promise<UpdateOrgIDPResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateOrgIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addOrgOIDCIDP(req: AddOrgOIDCIDPRequest): Promise<AddOrgOIDCIDPResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addOrgOIDCIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateOrgIDPOIDCConfig(req: UpdateOrgIDPOIDCConfigRequest): Promise<UpdateOrgIDPOIDCConfigResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateOrgIDPOIDCConfig(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public removeOrgIDP(idpId: string): Promise<RemoveOrgIDPResponse.AsObject> {
|
||||
const req = new RemoveOrgIDPRequest();
|
||||
req.setIdpId(idpId);
|
||||
@@ -884,12 +851,44 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.reactivateOrgIDP(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addOrgJWTIDP(req: AddOrgJWTIDPRequest): Promise<AddOrgJWTIDPResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addOrgJWTIDP(req, null).then((resp) => resp.toObject());
|
||||
// idp templates
|
||||
|
||||
public addGoogleProvider(req: AddGoogleProviderRequest): Promise<AddGoogleProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addGoogleProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateOrgIDPJWTConfig(req: UpdateOrgIDPJWTConfigRequest): Promise<UpdateOrgIDPJWTConfigResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateOrgIDPJWTConfig(req, null).then((resp) => resp.toObject());
|
||||
public updateGoogleProvider(req: UpdateGoogleProviderRequest): Promise<UpdateGoogleProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateGoogleProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGenericOIDCProvider(req: AddGenericOIDCProviderRequest): Promise<AddGenericOIDCProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateGenericOIDCProvider(
|
||||
req: UpdateGenericOIDCProviderRequest,
|
||||
): Promise<UpdateGenericOIDCProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addJWTProvider(req: AddJWTProviderRequest): Promise<AddJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateJWTProvider(req: UpdateJWTProviderRequest): Promise<UpdateJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public deleteProvider(req: DeleteProviderRequest): Promise<DeleteProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.deleteProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listProviders(req: ListProvidersRequest): Promise<ListProvidersResponse.AsObject> {
|
||||
return this.grpcService.mgmt.listProviders(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getProviderByID(req: GetProviderByIDRequest): Promise<GetProviderByIDResponse.AsObject> {
|
||||
return this.grpcService.mgmt.getProviderByID(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addHumanUser(req: AddHumanUserRequest): Promise<AddHumanUserResponse.AsObject> {
|
||||
|
||||
Reference in New Issue
Block a user