diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 6d03aafdb..6fd9ac34e 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -485,7 +485,7 @@ message.restoring-this-version-will-copy=Restoring this version will copy the Ve message.invalid-regex-pattern=Invalid Regular Expression -message.invalid-signing=Warning! If neither the Assertions or the Response are signed the service will not be able to verify a SAML response from the Identity Provider. +message.invalid-signing=Unless the response or the assertions are signed, SAML security is compromised and the service should reject the SAML response. (If it doesn\u0027t, investigate, as that is serious unless the HTTP-Artifact binding is in use.) tooltip.entity-id=Entity ID tooltip.service-provider-name=Service Provider Name (Dashboard Display Only) diff --git a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.spec.ts b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.spec.ts index c013dcd18..4bcca0481 100644 --- a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.spec.ts +++ b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.spec.ts @@ -57,13 +57,14 @@ describe('Metadata Source Base class', () => { code: 'INVALID_SIGNING', path: `#/relyingPartyOverrides`, message: 'message.invalid-signing', - params: [relyingPartyOverrides] + params: [relyingPartyOverrides], + invalidate: false }; spyOn(validators, '/relyingPartyOverrides').and.returnValue(error); const validated = validator(value, null, { getProperty: getPropertySpy }); - expect(validated).toEqual([error]); + expect(validated).toBeUndefined(); }); }); @@ -76,7 +77,8 @@ describe('Metadata Source Base class', () => { code: 'INVALID_SIGNING', path: `#/relyingPartyOverrides`, message: 'message.invalid-signing', - params: [relyingPartyOverrides] + params: [relyingPartyOverrides], + invalidate: false }; const validated = validator(relyingPartyOverrides, {path: '/relyingPartyOverrides'}); diff --git a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts index 557733390..6cfd285c8 100644 --- a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts +++ b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts @@ -79,7 +79,7 @@ export class MetadataSourceBase implements Wizard { const validatorKey = `/${key}`; const validator = validators.hasOwnProperty(validatorKey) ? validators[validatorKey] : null; const error = validator ? validator(item, form_current.getProperty(key), form_current) : null; - if (error) { + if (error && error.invalidate) { errors = errors || []; errors.push(error); } @@ -91,7 +91,8 @@ export class MetadataSourceBase implements Wizard { code: 'INVALID_ID', path: `#${property.path}`, message: 'message.id-unique', - params: [value] + params: [value], + invalidate: true } : null; return err; }, @@ -101,7 +102,8 @@ export class MetadataSourceBase implements Wizard { code: 'INVALID_SIGNING', path: `#${property.path}`, message: 'message.invalid-signing', - params: [value] + params: [value], + invalidate: false }; } return null; @@ -112,7 +114,8 @@ export class MetadataSourceBase implements Wizard { code: 'PROTOCOL_SUPPORT_ENUM_REQUIRED', path: `#${property.path}`, message: 'message.protocol-support-required', - params: [value] + params: [value], + invalidate: true }; } return null; diff --git a/ui/src/app/metadata/filter/model/entity-attributes.filter.spec.ts b/ui/src/app/metadata/filter/model/entity-attributes.filter.spec.ts index a5505284d..552b94023 100644 --- a/ui/src/app/metadata/filter/model/entity-attributes.filter.spec.ts +++ b/ui/src/app/metadata/filter/model/entity-attributes.filter.spec.ts @@ -6,6 +6,7 @@ describe('Entity Attributes filter form', () => { expect(Object.keys(EntityAttributesFilter.getValidators())).toEqual([ '/', '/name', + '/relyingPartyOverrides', '/entityAttributesFilterTarget' ]); }); diff --git a/ui/src/app/metadata/filter/model/entity-attributes.filter.ts b/ui/src/app/metadata/filter/model/entity-attributes.filter.ts index f1d58d915..a4b18b67a 100644 --- a/ui/src/app/metadata/filter/model/entity-attributes.filter.ts +++ b/ui/src/app/metadata/filter/model/entity-attributes.filter.ts @@ -26,7 +26,7 @@ export const EntityAttributesFilter: FormDefinition = { const validatorKey = `/${key}`; const validator = validators.hasOwnProperty(validatorKey) ? validators[validatorKey] : null; const error = validator ? validator(item, { path: `/${key}` }, form_current) : null; - if (error) { + if (error && error.invalidate) { errors = errors || []; errors.push(error); } @@ -38,10 +38,23 @@ export const EntityAttributesFilter: FormDefinition = { code: 'INVALID_NAME', path: `#${property.path}`, message: 'message.name-must-be-unique', - params: [value] + params: [value], + invalidate: true } : null; return err; }, + '/relyingPartyOverrides': (value, property, form) => { + if (!value.signAssertion && value.dontSignResponse) { + return { + code: 'INVALID_SIGNING', + path: `#${property.path}`, + message: 'message.invalid-signing', + params: [value], + invalidate: false + }; + } + return null; + }, '/entityAttributesFilterTarget': (value, property, form) => { if (!form || !form.value || !form.value.entityAttributesFilterTarget || form.value.entityAttributesFilterTarget.entityAttributesFilterTargetType !== 'REGEX') { @@ -51,9 +64,10 @@ export const EntityAttributesFilter: FormDefinition = { code: 'INVALID_REGEX', path: `#${property.path}`, message: 'message.invalid-regex-pattern', - params: [value.value[0]] + params: [value.value[0]], + invalidate: true }; - } + }, }; return validators; }, diff --git a/ui/src/app/metadata/provider/model/dynamic-http.provider.form.ts b/ui/src/app/metadata/provider/model/dynamic-http.provider.form.ts index 2096ac38b..395bf56e1 100644 --- a/ui/src/app/metadata/provider/model/dynamic-http.provider.form.ts +++ b/ui/src/app/metadata/provider/model/dynamic-http.provider.form.ts @@ -2,6 +2,10 @@ import { Wizard } from '../../../wizard/model'; import { DynamicHttpMetadataProvider } from '../../domain/model/providers/dynamic-http-metadata-provider'; import { BaseMetadataProviderEditor } from './base.provider.form'; import { metadataFilterProcessor } from './utilities'; +import RegexValidator from '../../../shared/validation/regex.validator'; +import { memoize } from '../../../shared/memo'; + +const checkRegex = memoize(RegexValidator.isValidRegex); export const DynamicHttpMetadataProviderWizard: Wizard = { ...BaseMetadataProviderEditor, @@ -50,13 +54,30 @@ export const DynamicHttpMetadataProviderWizard: Wizard