mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-06 13:57:41 +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:
parent
2efa305e10
commit
2ee381f414
@ -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');
|
||||
}
|
||||
}
|
@ -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 {}
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 {}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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');
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
@ -159,6 +159,7 @@
|
||||
"NEXT": "Weiter",
|
||||
"MORE": "mehr",
|
||||
"STEP": "Schritt",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Zeige Benutzer {{value}}"
|
||||
}
|
||||
@ -1614,15 +1615,38 @@
|
||||
"ACTIVETITLE": "Aktive Identitäts Provider"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "Neuer Identitäts Provider",
|
||||
"DESCRIPTION": "Wählen Sie einen der folgenden Typen von Identitäts Providern"
|
||||
"TITLE": "Provider hinzufügen",
|
||||
"DESCRIPTION": "Wähle einen der verfügbaren Provider.",
|
||||
"STEPPERTITLE": "Provider hinzufügen",
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Geben Sie die erforderlichen Daten für Ihren OIDC-Provider ein."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Geben Sie die erforderlichen Daten für Ihren JWT-Provider ein."
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Google Provider",
|
||||
"DESCRIPTION": "Geben Sie die erforderlichen Daten für Ihren Google-Identitätsprovider ein."
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "Identitäts Provider",
|
||||
"DESCRIPTION": "Generelle Konfiguration deines Identitäts Providers",
|
||||
"DESCRIPTION": "Bearbeite deine Providerkonfiguration",
|
||||
"DATECREATED": "Erstellt",
|
||||
"DATECHANGED": "Geändert"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "Automatisches Erstellen",
|
||||
"ISAUTOCREATION_DESC": "Legt fest ob ein Konto erstellt wird, falls es noch nicht existiert.",
|
||||
"ISAUTOUPDATE": "Automatisches Update",
|
||||
"ISAUTOUPDATE_DESC": "Legt fest ob Konten bei der erneuten Authentifizierung aktualisiert werden.",
|
||||
"ISCREATIONALLOWED": "Account erstellen erlaubt",
|
||||
"ISCREATIONALLOWED_DESC": "Legt fest, ob Konten erstellt werden können.",
|
||||
"ISLINKINGALLOWED": "Account linking erlaubt",
|
||||
"ISLINKINGALLOWED_DESC": "Legt fest, ob eine Identität mit einem bestehenden Konto verknüpft werden kann."
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "unknown",
|
||||
"1": "Instanz",
|
||||
@ -1637,18 +1661,10 @@
|
||||
"1": "aktiv",
|
||||
"2": "inaktiv"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "Preferred Username",
|
||||
"2": "Email"
|
||||
},
|
||||
"STYLE": "Style",
|
||||
"STYLEFIELD": {
|
||||
"0": "kein Styling",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "Wenn angegeben, wir er im Login interface angezeigt.",
|
||||
"OPTIONAL": "optional",
|
||||
"UPDATECLIENTSECRET": "Client Secret updaten",
|
||||
"ADD": "Identity Provider hinzufügen",
|
||||
"AUTOREGISTER": "Automatische Registrierung",
|
||||
"AUTOREGISTER_DESC": "Wenn aktiviert und noch kein Account vorhanden ist, wird einer für den entsprechenden Benutzer erstellt.",
|
||||
"TYPE": "Typ",
|
||||
"OWNER": "Besitzer",
|
||||
"ID": "ID",
|
||||
|
@ -160,6 +160,7 @@
|
||||
"MORE": "more",
|
||||
"STEP": "Step",
|
||||
"SETUP": "Setup",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Show user {{value}}"
|
||||
}
|
||||
@ -1615,41 +1616,51 @@
|
||||
"ACTIVETITLE": "Active Identity Providers"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "New Identity Provider",
|
||||
"DESCRIPTION": "Choose one of the following Identity Provider types."
|
||||
"TITLE": "Add provider",
|
||||
"DESCRIPTION": "Select one ore more of the following providers.",
|
||||
"STEPPERTITLE": "Create Provider",
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Enter the required data for your OIDC provider."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Enter the required data for your JWT provider."
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Google Provider",
|
||||
"DESCRIPTION": "Enter the credentials for your Google Identity Provider"
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "Identity Provider",
|
||||
"DESCRIPTION": "General Configuration of your identity provider.",
|
||||
"DESCRIPTION": "Update your provider configuration",
|
||||
"DATECREATED": "Created",
|
||||
"DATECHANGED": "Changed"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "Automatic creation",
|
||||
"ISAUTOCREATION_DESC": "If selected, an account will be created if it does not exist yet.",
|
||||
"ISAUTOUPDATE": "Automatic update",
|
||||
"ISAUTOUPDATE_DESC": "If selected, accounts are updated on reauthentication.",
|
||||
"ISCREATIONALLOWED": "Account creation allowed",
|
||||
"ISCREATIONALLOWED_DESC": "Determines whether accounts can be created.",
|
||||
"ISLINKINGALLOWED": "Account linking allowed",
|
||||
"ISLINKINGALLOWED_DESC": "Determines whether an identity can be linked to an existing account."
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "unknown",
|
||||
"1": "Instance",
|
||||
"2": "Organization"
|
||||
},
|
||||
"TYPES": {
|
||||
"0": "unknown",
|
||||
"1": "OIDC",
|
||||
"3": "JWT"
|
||||
},
|
||||
"STATES": {
|
||||
"1": "active",
|
||||
"2": "inactive"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "Preferred Username",
|
||||
"2": "Email"
|
||||
},
|
||||
"STYLE": "Style",
|
||||
"STYLEFIELD": {
|
||||
"0": "No Styling",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "If specified it will be shown in the login interface.",
|
||||
"OPTIONAL": "optional",
|
||||
"UPDATECLIENTSECRET": "update client secret",
|
||||
"ADD": "Add Identity Provider",
|
||||
"AUTOREGISTER": "Auto Register",
|
||||
"AUTOREGISTER_DESC": "If selected and no account exists yet, one will be created.",
|
||||
"TYPE": "Type",
|
||||
"OWNER": "Owner",
|
||||
"ID": "ID",
|
||||
|
@ -159,6 +159,7 @@
|
||||
"NEXT": "Suivant",
|
||||
"MORE": "plus",
|
||||
"STEP": "Étape",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Afficher l'utilisateur{{value}}"
|
||||
}
|
||||
@ -1614,15 +1615,38 @@
|
||||
"ACTIVETITLE": "Fournisseurs d'identité actifs"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "Nouveau fournisseur d'identité",
|
||||
"DESCRIPTION": "Choisissez l'un des types de fournisseur d'identité suivants."
|
||||
"TITLE": "Ajouter un fournisseur",
|
||||
"DESCRIPTION": "Sélectionnez un ou plusieurs des fournisseurs suivants.",
|
||||
"STEPPERTITLE": "Créer un fournisseur",
|
||||
"OIDC": {
|
||||
"TITLE": "Fournisseur OIDC",
|
||||
"DESCRIPTION": "Entrez les données requises pour votre fournisseur OIDC."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "Fournisseur JWT",
|
||||
"DESCRIPTION": "Entrez les données requises pour votre fournisseur JWT."
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Fournisseur Google",
|
||||
"DESCRIPTION": "Saisissez les informations d'identification de votre fournisseur d'identité Google"
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "Fournisseur d'identité",
|
||||
"DESCRIPTION": "Configuration générale de votre fournisseur d'identité.",
|
||||
"DESCRIPTION": "Mettez à jour la configuration de votre fournisseur",
|
||||
"DATECREATED": "Créé",
|
||||
"DATECHANGED": "Modifié"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "Création automatique",
|
||||
"ISAUTOCREATION_DESC": "Détermine si un compte sera créé s'il n'existe pas déjà.",
|
||||
"ISAUTOUPDATE": "est mise à jour automatiquement",
|
||||
"ISAUTOUPDATE_DESC": "Si cette option est sélectionnée, les comptes sont mis à jour lors de la réauthentification.",
|
||||
"ISCREATIONALLOWED": "la création est-elle autorisée",
|
||||
"ISCREATIONALLOWED_DESC": "Détermine si des comptes peuvent être créés.",
|
||||
"ISLINKINGALLOWED": "la liaison est-elle autorisée",
|
||||
"ISLINKINGALLOWED_DESC": "Détermine si une identité peut être liée à un compte existant."
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "inconnu",
|
||||
"1": "Instance",
|
||||
@ -1637,18 +1661,10 @@
|
||||
"1": "actif",
|
||||
"2": "inactif"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "Nom d'utilisateur préféré",
|
||||
"2": "Courriel"
|
||||
},
|
||||
"STYLE": "Style",
|
||||
"STYLEFIELD": {
|
||||
"0": "Pas de style",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "Si elle est spécifiée, elle sera affichée dans l'interface de connexion.",
|
||||
"OPTIONAL": "optionnel",
|
||||
"UPDATECLIENTSECRET": "mise à jour du secret client",
|
||||
"ADD": "Ajouter un fournisseur d'identité",
|
||||
"AUTOREGISTER": "Enregistrement automatique",
|
||||
"AUTOREGISTER_DESC": "Si cette option est sélectionnée et qu'aucun compte n'existe encore, un compte sera créé.",
|
||||
"TYPE": "Type",
|
||||
"OWNER": "Propriétaire",
|
||||
"ID": "ID",
|
||||
|
@ -159,6 +159,7 @@
|
||||
"NEXT": "Avanti",
|
||||
"MORE": "azioni",
|
||||
"STEP": "Passo",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Mostra utente {{value}}"
|
||||
}
|
||||
@ -1615,15 +1616,38 @@
|
||||
"ACTIVETITLE": "Identity Providers"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "Nuovo IDP",
|
||||
"DESCRIPTION": "Configura l'endpoint del tuo nuovo IDP."
|
||||
"TITLE": "Aggiungi provider",
|
||||
"DESCRIPTION": "Seleziona uno dei seguenti provider.",
|
||||
"STEPPERTITLE": "Create Provider",
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo provider OIDC."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo provider JWT."
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Google Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo Google provider."
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "Identity Provider",
|
||||
"DESCRIPTION": "Configurazione generale del tuo fornitore di identit\u00e0.",
|
||||
"DESCRIPTION": "Aggiorna la configurazione del tuo provider",
|
||||
"DATECREATED": "Creato",
|
||||
"DATECHANGED": "Cambiato"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "Creazione automatica",
|
||||
"ISAUTOCREATION_DESC": "Se selezionato, verrà creato un account se non esiste ancora.",
|
||||
"ISAUTOUPDATE": "Aggiornamento automatico",
|
||||
"ISAUTOUPDATE_DESC": "Se selezionato, gli account vengono aggiornati alla riautenticazione.",
|
||||
"ISCREATIONALLOWED": "Creazione consentita",
|
||||
"ISCREATIONALLOWED_DESC": "Determina se i conti possono essere creati.",
|
||||
"ISLINKINGALLOWED": "Collegamento consentito",
|
||||
"ISLINKINGALLOWED_DESC": "Determina se un'identità può essere collegata a un account esistente."
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "sconosciuto",
|
||||
"1": "Istanza",
|
||||
@ -1638,18 +1662,10 @@
|
||||
"1": "attivo",
|
||||
"2": "inattivo"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "Nome utente preferito",
|
||||
"2": "Email"
|
||||
},
|
||||
"STYLE": "Stile",
|
||||
"STYLEFIELD": {
|
||||
"0": "No Styling",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "Se specificato, verrà mostrato nell'interfaccia di accesso.",
|
||||
"OPTIONAL": "opzionale",
|
||||
"UPDATECLIENTSECRET": "Aggiorna secret",
|
||||
"ADD": "Aggiungi Identity Provider",
|
||||
"AUTOREGISTER": "Registrazione automatica",
|
||||
"AUTOREGISTER_DESC": "Se \u00e8 selezionato e non esiste ancora un account, ne verr\u00e0 creato uno.",
|
||||
"TYPE": "Tipo",
|
||||
"OWNER": "Owner",
|
||||
"ID": "ID",
|
||||
|
@ -159,6 +159,7 @@
|
||||
"NEXT": "Następny",
|
||||
"MORE": "więcej",
|
||||
"STEP": "Krok",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Pokaż użytkownika {{value}}"
|
||||
}
|
||||
@ -1614,15 +1615,38 @@
|
||||
"ACTIVETITLE": "Aktywni dostawcy tożsamości"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "Nowy dostawca tożsamości",
|
||||
"DESCRIPTION": "Wybierz jeden z poniższych typów dostawcy tożsamości."
|
||||
"TITLE": "Dodaj dostawcę",
|
||||
"DESCRIPTION": "Wybierz jednego lub więcej z następujących dostawców.",
|
||||
"STEPPERTITLE": "Utwórz dostawcę",
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Wprowadź wymagane dane dla swojego dostawcy OIDC."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Wprowadź wymagane dane dla swojego dostawcy JWT."
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "Google Provider",
|
||||
"DESCRIPTION": "Wprowadź dane dla swojego dostawcy tożsamości Google"
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "Dostawca tożsamości",
|
||||
"DESCRIPTION": "Ogólna konfiguracja dostawcy tożsamości.",
|
||||
"DESCRIPTION": "Aktualizacja konfiguracji dostawcy",
|
||||
"DATECREATED": "Utworzono",
|
||||
"DATECHANGED": "Zmieniono"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "Automatyczne tworzenie",
|
||||
"ISAUTOCREATION_DESC": "Jeśli zostanie wybrana, konto zostanie utworzone, jeśli jeszcze nie istnieje.",
|
||||
"ISAUTOUPDATE": "Automatyczna aktualizacja",
|
||||
"ISAUTOUPDATE_DESC": "Jeśli zaznaczone, konta są aktualizowane przy ponownym uwierzytelnianiu.",
|
||||
"ISCREATIONALLOWED": "tworzenie dozwolone",
|
||||
"ISCREATIONALLOWED_DESC": "Określa, czy można tworzyć konta.",
|
||||
"ISLINKINGALLOWED": "dozwolone łączenie rachunków",
|
||||
"ISLINKINGALLOWED_DESC": "Określa, czy tożsamość może być powiązana z istniejącym kontem."
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "nieznany",
|
||||
"1": "Instancja",
|
||||
@ -1637,18 +1661,10 @@
|
||||
"1": "aktywny",
|
||||
"2": "nieaktywny"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "Preferowana nazwa użytkownika",
|
||||
"2": "E-mail"
|
||||
},
|
||||
"STYLE": "Styl",
|
||||
"STYLEFIELD": {
|
||||
"0": "Bez stylizacji",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "Jeśli zostanie podany, będzie widoczny w interfejsie logowania.",
|
||||
"OPTIONAL": "opcjonalnie",
|
||||
"UPDATECLIENTSECRET": "aktualizacja tajemnicy klienta",
|
||||
"ADD": "Dodaj dostawcę tożsamości",
|
||||
"AUTOREGISTER": "Automatyczna rejestracja",
|
||||
"AUTOREGISTER_DESC": "Jeśli zaznaczone, a konto jeszcze nie istnieje, zostanie utworzone.",
|
||||
"TYPE": "Typ",
|
||||
"OWNER": "Właściciel",
|
||||
"ID": "ID",
|
||||
|
@ -159,6 +159,7 @@
|
||||
"NEXT": "下一页",
|
||||
"MORE": "更多",
|
||||
"STEP": "Step",
|
||||
"COMINGSOON": "Coming soon",
|
||||
"TABLE": {
|
||||
"SHOWUSER": "Show user {{value}}"
|
||||
}
|
||||
@ -1613,15 +1614,38 @@
|
||||
"ACTIVETITLE": "启用的身份提供者"
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "创建身份提供者",
|
||||
"DESCRIPTION": "选择以下身份提供者类型之一。"
|
||||
"TITLE": "创建供应商",
|
||||
"DESCRIPTION": "选择以下一个或多个供应商。",
|
||||
"STEPPERTITLE": "创建供应商",
|
||||
"OIDC": {
|
||||
"TITLE": "OIDC供应商",
|
||||
"DESCRIPTION": "输入你的OIDC供应商的必要数据。"
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT供应商",
|
||||
"DESCRIPTION": "输入你的JWT供应商所需的数据。"
|
||||
},
|
||||
"GOOGLE": {
|
||||
"TITLE": "谷歌供应商",
|
||||
"DESCRIPTION": "输入你的谷歌身份提供者的凭证"
|
||||
}
|
||||
},
|
||||
"DETAIL": {
|
||||
"TITLE": "身份提供者",
|
||||
"DESCRIPTION": "身份提供者的常规配置。",
|
||||
"DESCRIPTION": "更新你的供应商配置",
|
||||
"DATECREATED": "已创建",
|
||||
"DATECHANGED": "已更新"
|
||||
},
|
||||
"OPTIONS": {
|
||||
"ISAUTOCREATION": "是自动创建",
|
||||
"ISAUTOCREATION_DESC": "如果选择了,如果账户还不存在,就会创建一个账户。",
|
||||
"ISAUTOUPDATE": "正在自动更新",
|
||||
"ISAUTOUPDATE_DESC": "如果选择,账户将在重新认证时更新。",
|
||||
"ISCREATIONALLOWED": "是否允许创作",
|
||||
"ISCREATIONALLOWED_DESC": "确定是否可以创建账户。",
|
||||
"ISLINKINGALLOWED": "是否允许连接",
|
||||
"ISLINKINGALLOWED_DESC": "确定一个身份是否可以与一个现有的账户相联系。"
|
||||
},
|
||||
"OWNERTYPES": {
|
||||
"0": "未知",
|
||||
"1": "实例",
|
||||
@ -1636,18 +1660,10 @@
|
||||
"1": "启用",
|
||||
"2": "停用"
|
||||
},
|
||||
"MAPPINGFIELD": {
|
||||
"1": "首选用户名",
|
||||
"2": "电子邮箱"
|
||||
},
|
||||
"STYLE": "样式",
|
||||
"STYLEFIELD": {
|
||||
"0": "没有样式",
|
||||
"1": "Google"
|
||||
},
|
||||
"NAMEHINT": "如果指定,它将显示在登录界面。",
|
||||
"OPTIONAL": "可选",
|
||||
"UPDATECLIENTSECRET": "更新客户秘密",
|
||||
"ADD": "添加身份提供者",
|
||||
"AUTOREGISTER": "自动注册",
|
||||
"AUTOREGISTER_DESC": "如果勾选,当使用 IDP 登录且用户不存在时,则会创建一个。",
|
||||
"TYPE": "类型",
|
||||
"OWNER": "所有者",
|
||||
"ID": "ID",
|
||||
|
3
console/src/assets/images/idp/github-dark.svg
Normal file
3
console/src/assets/images/idp/github-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" transform="scale(64)" fill="#fafafa"/>
|
||||
</svg>
|
After Width: | Height: | Size: 968 B |
3
console/src/assets/images/idp/github.svg
Normal file
3
console/src/assets/images/idp/github.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" transform="scale(64)" fill="#1B1F23"/>
|
||||
</svg>
|
After Width: | Height: | Size: 968 B |
1
console/src/assets/images/idp/gitlab.svg
Normal file
1
console/src/assets/images/idp/gitlab.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="m24.507 9.5-.034-.09L21.082.562a.896.896.0 00-1.694.091l-2.29 7.01H7.825L5.535.653A.898.898.0 003.841.563L.451 9.411.416 9.5a6.297 6.297.0 002.09 7.278l.012.01.03.022 5.16 3.867 2.56 1.935 1.554 1.176a1.051 1.051.0 001.268.0l1.555-1.176 2.56-1.935 5.197-3.89.014-.01A6.297 6.297.0 0024.507 9.5z" fill="#e24329"/><path d="m24.507 9.5-.034-.09a11.44 11.44.0 00-4.56 2.051l-7.447 5.632 4.742 3.584 5.197-3.89.014-.01A6.297 6.297.0 0024.507 9.5z" fill="#fc6d26"/><path d="m7.707 20.677 2.56 1.935 1.555 1.176a1.051 1.051.0 001.268.0l1.555-1.176 2.56-1.935-4.743-3.584-4.755 3.584z" fill="#fca326"/><path d="M5.01 11.461A11.43 11.43.0 00.45 9.411L.416 9.5a6.297 6.297.0 002.09 7.278l.012.01.03.022 5.16 3.867 4.745-3.584-7.444-5.632z" fill="#fc6d26"/></svg>
|
After Width: | Height: | Size: 856 B |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
1
console/src/assets/images/idp/ms.svg
Normal file
1
console/src/assets/images/idp/ms.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"><title>MS-SymbolLockup</title><rect x="1" y="1" width="9" height="9" fill="#f25022"/><rect x="1" y="11" width="9" height="9" fill="#00a4ef"/><rect x="11" y="1" width="9" height="9" fill="#7fba00"/><rect x="11" y="11" width="9" height="9" fill="#ffb900"/></svg>
|
After Width: | Height: | Size: 343 B |
@ -53,12 +53,13 @@
|
||||
@import 'src/app/modules/sidenav/sidenav.component';
|
||||
@import 'src/app/modules/user-grants/user-grants.component.scss';
|
||||
@import 'src/app/modules/shortcuts/shortcuts.component.scss';
|
||||
@import 'src/app/modules/idp-create/idp-type-radio/idp-type-radio.component.scss';
|
||||
@import 'src/app/modules/policies/idp-settings/idp-settings.component.scss';
|
||||
@import 'src/app/pages/actions/add-action-dialog/add-action-dialog.component';
|
||||
@import 'src/app/modules/project-role-chip/project-role-chip.component';
|
||||
@import 'src/app/pages/events/events.component';
|
||||
@import 'src/app/pages/home/home.component.scss';
|
||||
@import 'src/app/modules/policies/security-policy/security-policy.component.scss';
|
||||
@import 'src/app/modules/idp-table/idp-table.component.scss';
|
||||
@import 'src/app/modules/search-user-autocomplete/search-user-autocomplete.component.scss';
|
||||
@import 'src/app/modules/policies/login-policy/factor-table/factor-table.component.scss';
|
||||
@import 'src/app/modules/info-overlay/info-overlay.component.scss';
|
||||
@ -72,9 +73,9 @@
|
||||
@include nav-toggle-theme($theme);
|
||||
@include header-theme($theme);
|
||||
@include app-type-radio-theme($theme);
|
||||
@include idp-table-theme($theme);
|
||||
@include events-theme($theme);
|
||||
@include projects-theme($theme);
|
||||
@include idp-type-radio-theme($theme);
|
||||
@include top-view-theme($theme);
|
||||
@include info-overlay-theme($theme);
|
||||
@include app-auth-method-radio-theme($theme);
|
||||
@ -82,6 +83,7 @@
|
||||
@include search-user-autocomplete-theme($theme);
|
||||
@include project-role-chips-theme($theme);
|
||||
@include card-theme($theme);
|
||||
@include idp-settings-theme($theme);
|
||||
@include filter-events-theme($theme);
|
||||
@include footer-theme($theme);
|
||||
@include table-theme($theme);
|
||||
|
Loading…
x
Reference in New Issue
Block a user