From 1c9ae89c1b8159bab64dfa17251860517bf9b0f5 Mon Sep 17 00:00:00 2001 From: Jodie Muramoto Date: Thu, 18 Oct 2018 13:17:22 -0700 Subject: [PATCH 1/6] SHIBUI-931: Corrected info text for useDefaultPredicateRegistry, satisfyAnyPredicates from the Shibboleth wiki; --- backend/src/main/resources/i18n/messages_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 6d64dd72a..fb8bff9c9 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -426,7 +426,7 @@ tooltip.backing-file=Specifies where the backing file is located. If the remote tooltip.backup-file-init-refresh-delay=Delay duration after which to schedule next HTTP refresh when initialized from the backing file. tooltip.require-valid-metadata=Whether candidate metadata found by the resolver must be valid in order to be returned (where validity is implementation specific, but in SAML cases generally depends on a validUntil attribute.) If this flag is true, then invalid candidate metadata will not be returned. tooltip.fail-fast-init=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does. -tooltip.use-default-predicate-reg=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does. +tooltip.use-default-predicate-reg=Flag which determines whether the default CriterionPredicateRegistry will be used if a custom one is not supplied explicitly. tooltip.satisfy-any-predicates=Flag which determines whether predicates used in filtering are connected by a logical 'OR' (true) or by logical 'AND' (false). tooltip.enable-provider-upon-saving=Enable Metadata Provider upon saving? From 45a8c7b591236630cd50b35bdf3bdf2bb4365db4 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 1 Nov 2018 13:25:53 -0700 Subject: [PATCH 2/6] SHIBUI-947 Fixed unsaved changes modal for resolver wizard --- .../component/unsaved-entity.dialog.html | 20 ++++++++++++++++--- .../domain/component/unsaved-entity.dialog.ts | 2 ++ .../container/resolver-wizard.component.ts | 11 +++++++--- .../app/metadata/resolver/resolver.routing.ts | 4 +++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html index 6c210c045..5966b73c8 100644 --- a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html +++ b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html @@ -1,14 +1,28 @@ - +
diff --git a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts index 7efe195c8..10180a2a8 100644 --- a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts +++ b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts @@ -10,6 +10,8 @@ import { Subject } from 'rxjs/Subject'; export class UnsavedEntityComponent { readonly subject: Subject = new Subject(); + @Input() message; + constructor( public activeModal: NgbActiveModal ) { } diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts index bf886ae6d..8c5685365 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -28,7 +28,7 @@ import { LoadSchemaRequest } from '../../../wizard/action/wizard.action'; import { UnsavedEntityComponent } from '../../domain/component/unsaved-entity.dialog'; import { ModalService } from '../../../core/service/modal.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { UpdateChanges } from '../action/entity.action'; +import { UpdateChanges, Clear } from '../action/entity.action'; @Component({ selector: 'resolver-wizard-page', @@ -127,6 +127,8 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat } )) ); + + this.changes$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(c => this.changes = c); } next(): void { @@ -173,9 +175,12 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat if (nextState.url.match('wizard')) { return of(true); } if (Object.keys(this.changes).length > 0) { let modal = this.modalService.open(UnsavedEntityComponent); - modal.componentInstance.action = new UpdateChanges(this.latest); + modal.componentInstance.message = 'resolver'; modal.result.then( - () => this.router.navigate([nextState.url]), + () => { + this.store.dispatch(new Clear()); + this.router.navigate([nextState.url]); + }, () => console.warn('denied') ); } diff --git a/ui/src/app/metadata/resolver/resolver.routing.ts b/ui/src/app/metadata/resolver/resolver.routing.ts index 5312f5537..1d080bd5f 100644 --- a/ui/src/app/metadata/resolver/resolver.routing.ts +++ b/ui/src/app/metadata/resolver/resolver.routing.ts @@ -26,7 +26,9 @@ export const ResolverRoutes: Routes = [ { path: 'blank/:index', component: ResolverWizardComponent, - canDeactivate: [], + canDeactivate: [ + CanDeactivateGuard + ], children: [ { path: '', From 47d65b39666db047d8363cf14905d7720289eeff Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 5 Nov 2018 11:58:25 -0700 Subject: [PATCH 3/6] SHIBUI Fixed issues to accomodate multiple types of providers --- .../container/provider-wizard-step.component.ts | 6 ++++-- .../app/metadata/provider/model/base.provider.form.ts | 9 --------- .../model/file-backed-http.provider.form.spec.ts | 4 ++-- .../provider/model/file-backed-http.provider.form.ts | 10 ++++++++++ ui/src/app/metadata/provider/model/provider.form.ts | 10 ++++++++++ ui/src/app/wizard/reducer/index.ts | 5 ++++- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts b/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts index 05d121bba..9ff4ded23 100644 --- a/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts +++ b/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy } from '@angular/core'; import { Observable, Subject } from 'rxjs'; -import { withLatestFrom, map, distinctUntilChanged, skipWhile } from 'rxjs/operators'; +import { withLatestFrom, map, distinctUntilChanged, skipWhile, filter } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import * as fromProvider from '../reducer'; @@ -42,7 +42,9 @@ export class ProviderWizardStepComponent implements OnDestroy { constructor( private store: Store, ) { - this.schema$ = this.store.select(fromWizard.getParsedSchema); + this.schema$ = this.store.select(fromWizard.getSchema).pipe( + filter(s => s && Object.keys(s.properties).length > 0) + ); this.definition$ = this.store.select(fromWizard.getWizardDefinition); this.changes$ = this.store.select(fromProvider.getEntityChanges); diff --git a/ui/src/app/metadata/provider/model/base.provider.form.ts b/ui/src/app/metadata/provider/model/base.provider.form.ts index 459eaa956..ecbcab666 100644 --- a/ui/src/app/metadata/provider/model/base.provider.form.ts +++ b/ui/src/app/metadata/provider/model/base.provider.form.ts @@ -1,6 +1,5 @@ import { Wizard } from '../../../wizard/model'; import { BaseMetadataProvider } from '../../domain/model/providers'; -import { UriValidator } from '../../../shared/validation/uri.validator'; export const BaseMetadataProviderEditor: Wizard = { label: 'BaseMetadataProvider', @@ -30,14 +29,6 @@ export const BaseMetadataProviderEditor: Wizard = { params: [value] } : null; return err; - }, - '/metadataURL': (value, property, form) => { - return !UriValidator.isUri(value) ? { - code: 'INVALID_URI', - path: `#${property.path}`, - message: 'message.uri-valid-format', - params: [value] - } : null; } }; return validators; diff --git a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts index aa07918f0..68e19359b 100644 --- a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts +++ b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts @@ -113,8 +113,8 @@ describe('FileBackedHttpMetadataProviderWizard', () => { expect(Object.keys(getValidators([]))).toEqual([ '/', '/name', - '/metadataURL', - '/xmlId' + '/xmlId', + '/metadataURL' ]); }); }); diff --git a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts index 2c8103438..8dbe80204 100644 --- a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts +++ b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts @@ -1,6 +1,7 @@ import { Wizard } from '../../../wizard/model'; import { FileBackedHttpMetadataProvider } from '../../domain/model/providers/file-backed-http-metadata-provider'; import { BaseMetadataProviderEditor } from './base.provider.form'; +import UriValidator from '../../../shared/validation/uri.validator'; export const FileBackedHttpMetadataProviderWizard: Wizard = { ...BaseMetadataProviderEditor, @@ -17,6 +18,15 @@ export const FileBackedHttpMetadataProviderWizard: Wizard { + return !UriValidator.isUri(value) ? { + code : 'INVALID_URI', + path: `#${property.path}`, + message: 'message.uri-valid-format', + params: [value] + } : null; + }; + return validators; }, steps: [ diff --git a/ui/src/app/metadata/provider/model/provider.form.ts b/ui/src/app/metadata/provider/model/provider.form.ts index 28e5794c5..71ba6174b 100644 --- a/ui/src/app/metadata/provider/model/provider.form.ts +++ b/ui/src/app/metadata/provider/model/provider.form.ts @@ -17,6 +17,16 @@ export const MetadataProviderWizard: Wizard = { fields: [ 'name', '@type' + ], + fieldsets: [ + { + type: 'section', + class: ['col-12'], + fields: [ + 'name', + '@type' + ] + } ] } ] as WizardStep[] diff --git a/ui/src/app/wizard/reducer/index.ts b/ui/src/app/wizard/reducer/index.ts index 0d7176565..56054616c 100644 --- a/ui/src/app/wizard/reducer/index.ts +++ b/ui/src/app/wizard/reducer/index.ts @@ -61,12 +61,15 @@ export const getSplitSchema = (schema: any, step: WizardStep) => { const required = (schema.required || []).filter(val => keys.indexOf(val) > -1); let s: any = { type: schema.type, - definitions: schema.definitions, properties: { ...keys.reduce( (properties, key) => ({ ...properties, [key]: schema.properties[key] }) , {}) } }; + if (schema.definitions) { + s.definitions = schema.definitions; + } + if (required && required.length) { s.required = required; } From 6f5a1f37e26e1da88adb7e5ccedfcfe180c57528 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 5 Nov 2018 14:48:11 -0700 Subject: [PATCH 4/6] SHIBUI-971 Fixed issue with creating source --- .../metadata/resolver/container/resolver-wizard.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts index 8c5685365..ba2221fda 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -172,7 +172,7 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat currentState: RouterStateSnapshot, nextState: RouterStateSnapshot ): Observable { - if (nextState.url.match('wizard')) { return of(true); } + if (nextState.url.match('blank')) { return of(true); } if (Object.keys(this.changes).length > 0) { let modal = this.modalService.open(UnsavedEntityComponent); modal.componentInstance.message = 'resolver'; From 10ec71c3902b550baed0586896df7e05af99e534 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Tue, 6 Nov 2018 16:50:14 -0700 Subject: [PATCH 5/6] [SHIBUI-906] Fixed a typo: Shematype -> SchemaType Pulled json generation out of controllers and in to a service. Added new controller for building Entity Attributes Filter schema. Added a "definition" block to the EAF schema json. Not sure we're keeping it though. Need to check with Ryan. --- ...ibutesFiltersUiDefinitionController.groovy | 61 +++++++++++++++++++ ...tadataSourcesUiDefinitionController.groovy | 61 ++----------------- ...sonSchemaValidatingControllerAdvice.groovy | 2 - .../service/JsonSchemaBuilderService.groovy | 61 +++++++++++++++++++ .../JsonSchemaComponentsConfiguration.java | 11 +++- ...oryJsonSchemaResourceLocationRegistry.java | 8 +-- .../jsonschema/JsonSchemaLocationLookup.java | 16 ++++- .../JsonSchemaResourceLocation.java | 2 +- .../JsonSchemaResourceLocationRegistry.java | 4 +- .../entity-attributes-filters-ui-schema.json | 4 +- ...efinitionControllerIntegrationTests.groovy | 2 +- 11 files changed, 161 insertions(+), 71 deletions(-) create mode 100644 backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityAttributesFiltersUiDefinitionController.groovy create mode 100644 backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityAttributesFiltersUiDefinitionController.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityAttributesFiltersUiDefinitionController.groovy new file mode 100644 index 000000000..ffd3ee3ab --- /dev/null +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityAttributesFiltersUiDefinitionController.groovy @@ -0,0 +1,61 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller + +import com.fasterxml.jackson.databind.ObjectMapper +import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation +import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry +import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +import javax.annotation.PostConstruct + +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.entityAttributesFiltersSchema +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR + +/** + * Controller implementing REST resource responsible for exposing structure definition for metadata sources user + * interface in terms of JSON schema. + * + * @author Dmitriy Kopylenko + * @author Bill Smith (wsmith@unicon.net) + */ +@RestController +@RequestMapping('/api/ui/EntityAttributesFilters') +class EntityAttributesFiltersUiDefinitionController { + + @Autowired + JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry + + JsonSchemaResourceLocation jsonSchemaLocation + + @Autowired + ObjectMapper jacksonObjectMapper + + @Autowired + JsonSchemaBuilderService jsonSchemaBuilderService + + @GetMapping + ResponseEntity getUiDefinitionJsonSchema() { + try { + def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map) + jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget']) + jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides']) + jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"]) + return ResponseEntity.ok(parsedJson) + } + catch (Exception e) { + e.printStackTrace() + return ResponseEntity.status(INTERNAL_SERVER_ERROR) + .body([jsonParseError : e.getMessage(), + sourceUiSchemaDefinitionFile: this.jsonSchemaLocation.url]) + } + } + + @PostConstruct + void init() { + this.jsonSchemaLocation = entityAttributesFiltersSchema(this.jsonSchemaResourceLocationRegistry); + } +} diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataSourcesUiDefinitionController.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataSourcesUiDefinitionController.groovy index 1425b5af1..5e8710220 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataSourcesUiDefinitionController.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataSourcesUiDefinitionController.groovy @@ -1,11 +1,9 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import com.fasterxml.jackson.databind.ObjectMapper -import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration -import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry -import org.springframework.beans.factory.BeanInitializationException +import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -15,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController import javax.annotation.PostConstruct import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.metadataSourcesSchema -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR /** @@ -38,15 +35,15 @@ class MetadataSourcesUiDefinitionController { ObjectMapper jacksonObjectMapper @Autowired - CustomPropertiesConfiguration customPropertiesConfiguration + JsonSchemaBuilderService jsonSchemaBuilderService @GetMapping ResponseEntity getUiDefinitionJsonSchema() { try { def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map) - addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget']) - addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides']) - addRelyingPartyOverridesCollectionDefinitions(parsedJson["definitions"]) + jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget']) + jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides']) + jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"]) return ResponseEntity.ok(parsedJson) } catch (Exception e) { @@ -61,52 +58,4 @@ class MetadataSourcesUiDefinitionController { void init() { this.jsonSchemaLocation = metadataSourcesSchema(this.jsonSchemaResourceLocationRegistry); } - - private void addReleaseAttributesToJson(Object json) { - json['data'] = customPropertiesConfiguration.getAttributes().collect { - [key: it['name'], label: it['displayName']] - } - } - - private void addRelyingPartyOverridesToJson(Object json) { - def properties = [:] - customPropertiesConfiguration.getOverrides().each { - def property - if (it['displayType'] == 'list' - || it['displayType'] == 'set') { - property = [$ref: '#/definitions/' + it['name']] - } else { - property = - [title : it['displayName'], - description: it['helpText'], - type : it['displayType'], - default : it['defaultValue']] - } - properties[(String) it['name']] = property - } - json['properties'] = properties - } - - private void addRelyingPartyOverridesCollectionDefinitions(Object json) { - customPropertiesConfiguration.getOverrides().stream().filter { - it -> it['displayType'] && (it['displayType'] == 'list' || it['displayType'] == 'set') - }.each { - def definition = [title : it['displayName'], - description: it['helpText'], - type : 'array', - default : null] - if (it['displayType'] == 'set') { - definition['uniqueItems'] = true - } else if (it['displayType'] == 'list') { - definition['uniqueItems'] = false - } - def items = [type : 'string', - minLength: '1', // TODO: should this be configurable? - maxLength: '255'] //TODO: or this? - items.widget = [id: 'datalist', data: it['defaultValues']] - - definition['items'] = items - json[(String) it['name']] = definition - } - } } diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy index cf342eef9..712142172 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/jsonschema/RelyingPartyOverridesJsonSchemaValidatingControllerAdvice.groovy @@ -2,7 +2,6 @@ package edu.internet2.tier.shibboleth.admin.ui.jsonschema import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation import mjson.Json -import org.springframework.beans.factory.BeanInitializationException import org.springframework.beans.factory.annotation.Autowired import org.springframework.core.MethodParameter import org.springframework.http.HttpInputMessage @@ -18,7 +17,6 @@ import javax.annotation.PostConstruct import java.lang.reflect.Type import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.metadataSourcesSchema -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES /** * Controller advice implementation for validating relying party overrides payload coming from UI layer diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy new file mode 100644 index 000000000..8af0be7d3 --- /dev/null +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JsonSchemaBuilderService.groovy @@ -0,0 +1,61 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration +import org.springframework.beans.factory.annotation.Autowired + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +class JsonSchemaBuilderService { + + @Autowired + CustomPropertiesConfiguration customPropertiesConfiguration + + void addReleaseAttributesToJson(Object json) { + json['data'] = customPropertiesConfiguration.getAttributes().collect { + [key: it['name'], label: it['displayName']] + } + } + + void addRelyingPartyOverridesToJson(Object json) { + def properties = [:] + customPropertiesConfiguration.getOverrides().each { + def property + if (it['displayType'] == 'list' + || it['displayType'] == 'set') { + property = [$ref: '#/definitions/' + it['name']] + } else { + property = + [title : it['displayName'], + description: it['helpText'], + type : it['displayType'], + default : it['defaultValue']] + } + properties[(String) it['name']] = property + } + json['properties'] = properties + } + + void addRelyingPartyOverridesCollectionDefinitionsToJson(Object json) { + customPropertiesConfiguration.getOverrides().stream().filter { + it -> it['displayType'] && (it['displayType'] == 'list' || it['displayType'] == 'set') + }.each { + def definition = [title : it['displayName'], + description: it['helpText'], + type : 'array', + default : null] + if (it['displayType'] == 'set') { + definition['uniqueItems'] = true + } else if (it['displayType'] == 'list') { + definition['uniqueItems'] = false + } + def items = [type : 'string', + minLength: '1', // TODO: should this be configurable? + maxLength: '255'] //TODO: or this? + items.widget = [id: 'datalist', data: it['defaultValues']] + + definition['items'] = items + json[(String) it['name']] = definition + } + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java index 8d70fa410..1bf2745c6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/JsonSchemaComponentsConfiguration.java @@ -1,8 +1,8 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; import com.fasterxml.jackson.databind.ObjectMapper; -import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation; import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry; +import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -10,8 +10,8 @@ import org.springframework.core.io.ResourceLoader; import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.*; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.ENTITY_ATTRIBUTES_FILTERS; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; /** * @author Dmitriy Kopylenko @@ -47,4 +47,9 @@ public JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(Res .build()); } + + @Bean + public JsonSchemaBuilderService jsonSchemaBuilderService() { + return new JsonSchemaBuilderService(); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/InMemoryJsonSchemaResourceLocationRegistry.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/InMemoryJsonSchemaResourceLocationRegistry.java index 56d6985bd..2840619b2 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/InMemoryJsonSchemaResourceLocationRegistry.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/InMemoryJsonSchemaResourceLocationRegistry.java @@ -14,18 +14,18 @@ */ class InMemoryJsonSchemaResourceLocationRegistry implements JsonSchemaResourceLocationRegistry { - private Map schemaLocations = - new EnumMap<>(JsonSchemaResourceLocation.ShemaType.class); + private Map schemaLocations = + new EnumMap<>(JsonSchemaResourceLocation.SchemaType.class); @Override - public JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.ShemaType type, JsonSchemaResourceLocation location) { + public JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.SchemaType type, JsonSchemaResourceLocation location) { this.schemaLocations.put(type, location); return this; } @Override - public Optional lookup(JsonSchemaResourceLocation.ShemaType type) { + public Optional lookup(JsonSchemaResourceLocation.SchemaType type) { return Optional.ofNullable(this.schemaLocations.get(type)); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java index 9208a1630..b9d9ac1f1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.jsonschema; -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS; +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES; /** * Utility methods for common JSON schema types lookups. @@ -21,4 +22,17 @@ public static JsonSchemaResourceLocation metadataSourcesSchema(JsonSchemaResourc .lookup(METADATA_SOURCES) .orElseThrow(() -> new IllegalStateException("JSON schema resource location for metadata sources is not registered.")); } + + /** + * Searches entity attributes filters JSON schema resource location object in the given location registry. + * + * @param resourceLocationRegistry + * @returnentity attributes filters JSON schema resource location object + * @throws IllegalStateException if schema is not found in the given registry + */ + public static JsonSchemaResourceLocation entityAttributesFiltersSchema(JsonSchemaResourceLocationRegistry resourceLocationRegistry) { + return resourceLocationRegistry + .lookup(ENTITY_ATTRIBUTES_FILTERS) + .orElseThrow(() -> new IllegalStateException("JSON schema resource location for metadata sources is not registered.")); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java index 0db5984bd..f08ac6069 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocation.java @@ -90,7 +90,7 @@ public static JsonSchemaResourceLocation newSchemaLocation(String jsonSchemaLoca } } - public enum ShemaType { + public enum SchemaType { METADATA_SOURCES, ENTITY_ATTRIBUTES_FILTERS } } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocationRegistry.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocationRegistry.java index 0882527d8..e5a6e88c5 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocationRegistry.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaResourceLocationRegistry.java @@ -16,7 +16,7 @@ public interface JsonSchemaResourceLocationRegistry { * @param type of JSON schema * @param location of JSON schema resource */ - JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.ShemaType type, JsonSchemaResourceLocation location); + JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.SchemaType type, JsonSchemaResourceLocation location); /** * Look up json schema resource location by given schema type. @@ -24,7 +24,7 @@ public interface JsonSchemaResourceLocationRegistry { * @param type type of JSON schema * @return optional location of JSON schema resource */ - Optional lookup(JsonSchemaResourceLocation.ShemaType type); + Optional lookup(JsonSchemaResourceLocation.SchemaType type); /** * Factory method. diff --git a/backend/src/main/resources/entity-attributes-filters-ui-schema.json b/backend/src/main/resources/entity-attributes-filters-ui-schema.json index 2350a345c..5d71f0ba8 100644 --- a/backend/src/main/resources/entity-attributes-filters-ui-schema.json +++ b/backend/src/main/resources/entity-attributes-filters-ui-schema.json @@ -222,5 +222,7 @@ "attributeRelease" ] } - ] + ], + "definitions": { + } } \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index 979f72a63..1da336ff2 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -12,7 +12,7 @@ import org.springframework.test.context.ActiveProfiles import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.* -import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES /** * @author Dmitriy Kopylenko From 2a4dc66181bdcab4553accf5240d74927561a551 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Wed, 7 Nov 2018 10:43:40 -0700 Subject: [PATCH 6/6] [SHIBUI-906] Simple unit test fix. Fixed messaging in an exception. --- .../admin/ui/jsonschema/JsonSchemaLocationLookup.java | 2 +- ...ataSourcesUiDefinitionControllerIntegrationTests.groovy | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java index b9d9ac1f1..e04dd72de 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaLocationLookup.java @@ -33,6 +33,6 @@ public static JsonSchemaResourceLocation metadataSourcesSchema(JsonSchemaResourc public static JsonSchemaResourceLocation entityAttributesFiltersSchema(JsonSchemaResourceLocationRegistry resourceLocationRegistry) { return resourceLocationRegistry .lookup(ENTITY_ATTRIBUTES_FILTERS) - .orElseThrow(() -> new IllegalStateException("JSON schema resource location for metadata sources is not registered.")); + .orElseThrow(() -> new IllegalStateException("JSON schema resource location for entity attributes filters is not registered.")); } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy index 1da336ff2..c881d81c7 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests.groovy @@ -12,6 +12,7 @@ import org.springframework.test.context.ActiveProfiles import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.* +import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES /** @@ -49,6 +50,12 @@ class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Speci .jacksonMapper(jacksonMapper) .detectMalformedJson(false) .build()) + .register(ENTITY_ATTRIBUTES_FILTERS, JsonSchemaLocationBuilder.with() + .jsonSchemaLocation('classpath:entity-attributes-filters-ui-schema.json') + .resourceLoader(resourceLoader) + .jacksonMapper(jacksonMapper) + .detectMalformedJson(false) + .build()) } } } \ No newline at end of file