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:
Max Peintner
2023-03-06 10:20:31 +00:00
committed by GitHub
parent 2efa305e10
commit 2ee381f414
55 changed files with 2217 additions and 1880 deletions
@@ -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;
}