From fc34896092420e502ec444309cb66b25e9f922cc Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:10:45 +0100 Subject: [PATCH] fix(cnsl): some saml provider issues (#7220) Co-authored-by: Max Peintner --- .../form-field/validators/validators.ts | 20 +++++++ .../provider-saml-sp.component.html | 9 ++- .../provider-saml-sp.component.scss | 3 + .../provider-saml-sp.component.ts | 59 ++++++++++++------- 4 files changed, 68 insertions(+), 23 deletions(-) diff --git a/console/src/app/modules/form-field/validators/validators.ts b/console/src/app/modules/form-field/validators/validators.ts index d3661d0dc6..f5f078433a 100644 --- a/console/src/app/modules/form-field/validators/validators.ts +++ b/console/src/app/modules/form-field/validators/validators.ts @@ -83,3 +83,23 @@ function i18nErr(err: ValidationErrors | null | undefined, i18nKey: string, para }; } } + +const isFieldEmpty = (fieldName: string, g: AbstractControl) => { + const field = g.get(fieldName)?.value; + if (typeof field === 'number') { + return field && field >= 0 ? true : false; + } + if (typeof field === 'string') { + return field && field.length > 0 ? true : false; + } + return false; +}; + +// Reference: https://stackoverflow.com/a/56057955 +export function atLeastOneIsFilled(...fields: string[]): ValidationErrors | null { + return (g: AbstractControl): ValidationErrors | null => { + return fields.some((fieldName) => isFieldEmpty(fieldName, g)) + ? null + : ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors); + }; +} diff --git a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html index ebf26ed303..19dcb177bc 100644 --- a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html +++ b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html @@ -21,7 +21,12 @@ {{ 'IDP.SAML.METADATAXML' | translate }} - + {{ 'IDP.SAML.METADATAURL' | translate }} @@ -29,7 +34,7 @@ {{ 'IDP.SAML.BINDING' | translate }} - + {{ binding }} diff --git a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.scss b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.scss index e69de29bb2..eb7c3b17ef 100644 --- a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.scss +++ b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.scss @@ -0,0 +1,3 @@ +.metadata-xml { + min-height: 200px; +} diff --git a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.ts b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.ts index 8723b98e36..1bfd6c4ab3 100644 --- a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.ts +++ b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.ts @@ -1,6 +1,6 @@ import { Component, Injector, Type } from '@angular/core'; import { Location } from '@angular/common'; -import { Options, Provider } from '../../../proto/generated/zitadel/idp_pb'; +import { Options, Provider, SAMLBinding } from '../../../proto/generated/zitadel/idp_pb'; import { AbstractControl, FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum'; import { ManagementService } from '../../../services/mgmt.service'; @@ -10,7 +10,7 @@ import { GrpcAuthService } from '../../../services/grpc-auth.service'; import { take } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; import { Breadcrumb, BreadcrumbService, BreadcrumbType } from '../../../services/breadcrumb.service'; -import { requiredValidator } from '../../form-field/validators/validators'; +import { atLeastOneIsFilled, requiredValidator } from '../../form-field/validators/validators'; import { AddSAMLProviderRequest as AdminAddSAMLProviderRequest, GetProviderByIDRequest as AdminGetProviderByIDRequest, @@ -21,7 +21,6 @@ import { GetProviderByIDRequest as MgmtGetProviderByIDRequest, UpdateSAMLProviderRequest as MgmtUpdateSAMLProviderRequest, } from 'src/app/proto/generated/zitadel/management_pb'; -import * as zitadel_idp_pb from '../../../proto/generated/zitadel/idp_pb'; @Component({ selector: 'cnsl-provider-saml-sp', @@ -38,7 +37,7 @@ export class ProviderSamlSpComponent { public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT; private service!: ManagementService | AdminService; - bindingValues: string[] = Object.keys(zitadel_idp_pb.SAMLBinding); + bindingValues: string[] = Object.keys(SAMLBinding); constructor( private _location: Location, @@ -54,13 +53,16 @@ export class ProviderSamlSpComponent { } private _initializeForm(): void { - this.form = new UntypedFormGroup({ - name: new UntypedFormControl('', [requiredValidator]), - metadataXml: new UntypedFormControl('', [requiredValidator]), - metadataUrl: new UntypedFormControl('', [requiredValidator]), - binding: new UntypedFormControl(this.bindingValues[0], [requiredValidator]), - withSignedRequest: new UntypedFormControl(true, [requiredValidator]), - }); + this.form = new UntypedFormGroup( + { + name: new UntypedFormControl('', [requiredValidator]), + metadataXml: new UntypedFormControl('', []), + metadataUrl: new UntypedFormControl('', []), + binding: new UntypedFormControl(this.bindingValues[0], [requiredValidator]), + withSignedRequest: new UntypedFormControl(true, [requiredValidator]), + }, + atLeastOneIsFilled('metadataXml', 'metadataUrl'), + ); } private _checkFormPermissions(): void { @@ -121,18 +123,23 @@ export class ProviderSamlSpComponent { this.serviceType === PolicyComponentServiceType.MGMT ? new MgmtUpdateSAMLProviderRequest() : new AdminUpdateSAMLProviderRequest(); + req.setId(this.provider.id); req.setName(this.name?.value); - req.setMetadataUrl(this.metadataUrl?.value); - req.setMetadataXml(this.metadataXml?.value); + if (this.metadataXml?.value) { + req.setMetadataXml(this.metadataXml?.value); + } else { + req.setMetadataUrl(this.metadataUrl?.value); + } + req.setWithSignedRequest(this.withSignedRequest?.value); // @ts-ignore - req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]); + req.setBinding(SAMLBinding[this.binding?.value]); req.setProviderOptions(this.options); this.loading = true; this.service .updateSAMLProvider(req) - .then((idp) => { + .then(() => { setTimeout(() => { this.loading = false; this.close(); @@ -151,16 +158,19 @@ export class ProviderSamlSpComponent { ? new MgmtAddSAMLProviderRequest() : new AdminAddSAMLProviderRequest(); req.setName(this.name?.value); - req.setMetadataUrl(this.metadataUrl?.value); - req.setMetadataXml(this.metadataXml?.value); + if (this.metadataXml?.value) { + req.setMetadataXml(this.metadataXml?.value); + } else { + req.setMetadataUrl(this.metadataUrl?.value); + } req.setProviderOptions(this.options); // @ts-ignore - req.setBinding(zitadel_idp_pb.SAMLBinding[`${this.biding?.value}`]); + req.setBinding(SAMLBinding[this.binding?.value]); req.setWithSignedRequest(this.withSignedRequest?.value); this.loading = true; this.service .addSAMLProvider(req) - .then((idp) => { + .then(() => { setTimeout(() => { this.loading = false; this.close(); @@ -187,9 +197,9 @@ export class ProviderSamlSpComponent { .then((resp) => { this.provider = resp.idp; this.loading = false; + this.name?.setValue(this.provider?.name); if (this.provider?.config?.saml) { this.form.patchValue(this.provider.config.saml); - this.name?.setValue(this.provider.name); } }) .catch((error) => { @@ -202,6 +212,13 @@ export class ProviderSamlSpComponent { this._location.back(); } + compareBinding(value: string, index: number) { + if (value) { + return value === Object.keys(SAMLBinding)[index]; + } + return false; + } + private get name(): AbstractControl | null { return this.form.get('name'); } @@ -214,7 +231,7 @@ export class ProviderSamlSpComponent { return this.form.get('metadataUrl'); } - private get biding(): AbstractControl | null { + private get binding(): AbstractControl | null { return this.form.get('binding'); }