feat(console): guide users when configuring IDPs (#7572)

* feat(console): show external idp remote config

* reuse copy-row

* finish google and saml sp

* finish apps

* add next steps modal

* rollout

* activate

* fix saml urls

* fix saml provider

* complete providers

* translate

* update google docs

* update entra id oidc docs

* update entra id saml docs

* update github docs

* update gitlab docs

* update apple docs

* update okta oidc docs

* update okta saml docs

* update keycloak docs

* update mocksaml

* cleanup

* lint

* lint

* fix overriden classes

* encapsulate styles

* fix icon classes

---------

Co-authored-by: peintnermax <max@caos.ch>
This commit is contained in:
Elio Bischof
2024-03-27 21:10:31 +01:00
committed by GitHub
parent 84644214d7
commit d26391a642
79 changed files with 1960 additions and 604 deletions

View File

@@ -0,0 +1,103 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, combineLatest, from, map, Observable, of, switchMap } from 'rxjs';
import { ManagementService } from './mgmt.service';
import { AddCustomLoginPolicyRequest, AddCustomLoginPolicyResponse } from '../proto/generated/zitadel/management_pb';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { IDPOwnerType, Provider } from '../proto/generated/zitadel/idp_pb';
import { AdminService } from './admin.service';
import { catchError } from 'rxjs/operators';
import { LoginPolicy } from '../proto/generated/zitadel/policy_pb';
@Injectable({
providedIn: 'root',
})
export class ActivateIdpService {
constructor() {}
public activateIdp(
service: AdminService | ManagementService,
id: string,
owner?: IDPOwnerType,
policy?: LoginPolicy.AsObject,
): Observable<any> {
const isAdmin = service instanceof AdminService;
if (isAdmin) {
service.addIDPToLoginPolicy(id);
}
if (!isAdmin && owner !== IDPOwnerType.IDP_OWNER_TYPE_SYSTEM && owner !== IDPOwnerType.IDP_OWNER_TYPE_ORG) {
throw new Error('Must specify owner for management service');
}
return from(service.addIDPToLoginPolicy(id!, owner!)).pipe(
catchError((error) => {
if (isAdmin || error.code != 5) {
throw error;
}
// No org policy was found, so we create a new one
return from(policy ? of(policy) : from(service.getLoginPolicy()).pipe(map((policy) => policy.policy))).pipe(
switchMap((policy) => {
if (!policy?.isDefault) {
// There is already an org policy
throw error;
}
return from(this.addLoginPolicy(service, policy)).pipe(
switchMap(() => from(service.addIDPToLoginPolicy(id!, owner!))),
);
}),
);
}),
);
}
public addLoginPolicy(
service: ManagementService,
policy: LoginPolicy.AsObject,
): Promise<AddCustomLoginPolicyResponse.AsObject> {
const mgmtreq = new AddCustomLoginPolicyRequest();
mgmtreq.setAllowExternalIdp(policy.allowExternalIdp);
mgmtreq.setAllowRegister(policy.allowRegister);
mgmtreq.setAllowUsernamePassword(policy.allowUsernamePassword);
mgmtreq.setForceMfa(policy.forceMfa);
mgmtreq.setPasswordlessType(policy.passwordlessType);
mgmtreq.setHidePasswordReset(policy.hidePasswordReset);
mgmtreq.setMultiFactorsList(policy.multiFactorsList);
mgmtreq.setSecondFactorsList(policy.secondFactorsList);
const pcl = new Duration()
.setSeconds(policy.passwordCheckLifetime?.seconds ?? 0)
.setNanos(policy.passwordCheckLifetime?.nanos ?? 0);
mgmtreq.setPasswordCheckLifetime(pcl);
const elcl = new Duration()
.setSeconds(policy.externalLoginCheckLifetime?.seconds ?? 0)
.setNanos(policy.externalLoginCheckLifetime?.nanos ?? 0);
mgmtreq.setExternalLoginCheckLifetime(elcl);
const misl = new Duration()
.setSeconds(policy.mfaInitSkipLifetime?.seconds ?? 0)
.setNanos(policy.mfaInitSkipLifetime?.nanos ?? 0);
mgmtreq.setMfaInitSkipLifetime(misl);
const sfcl = new Duration()
.setSeconds(policy.secondFactorCheckLifetime?.seconds ?? 0)
.setNanos(policy.secondFactorCheckLifetime?.nanos ?? 0);
mgmtreq.setSecondFactorCheckLifetime(sfcl);
const mficl = new Duration()
.setSeconds(policy.multiFactorCheckLifetime?.seconds ?? 0)
.setNanos(policy.multiFactorCheckLifetime?.nanos ?? 0);
mgmtreq.setMultiFactorCheckLifetime(mficl);
mgmtreq.setAllowDomainDiscovery(policy.allowDomainDiscovery);
mgmtreq.setIgnoreUnknownUsernames(policy.ignoreUnknownUsernames);
mgmtreq.setDefaultRedirectUri(policy.defaultRedirectUri);
mgmtreq.setDisableLoginWithEmail(policy.disableLoginWithEmail);
mgmtreq.setDisableLoginWithPhone(policy.disableLoginWithPhone);
mgmtreq.setForceMfaLocalOnly(policy.forceMfaLocalOnly);
return service.addCustomLoginPolicy(mgmtreq);
}
}

View File

@@ -34,14 +34,14 @@ export class EnvironmentService {
public admin!: AdminServiceClient;
private environment$: Observable<Environment>;
private wellKnown$: Observable<WellKnown>;
private wellknown$: Observable<WellKnown>;
constructor(
private http: HttpClient,
private exhaustedSvc: ExhaustedService,
) {
this.environment$ = this.createEnvironment();
this.wellKnown$ = this.createWellKnown(this.environment$);
this.wellknown$ = this.createWellKnown(this.environment$);
}
// env returns an `Observable<Environment>` that can be subscribed to whenever needed.
@@ -51,10 +51,10 @@ export class EnvironmentService {
return this.environment$;
}
// wellKnown returns an `Observable<Environment>` that can be subscribed to whenever needed.
// wellknown returns an `Observable<Environment>` that can be subscribed to whenever needed.
// It makes the HTTP call exactly once and replays the cached result.
get wellKnown() {
return this.wellKnown$;
get wellknown() {
return this.wellknown$;
}
private createEnvironment() {