diff --git a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy index 4a95484e8..c444bd214 100644 --- a/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy +++ b/backend/src/main/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImpl.groovy @@ -10,7 +10,11 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetada import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FilesystemMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataQueryProtocolScheme +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataRequestURLConstructionScheme +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.RegexScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.TemplateScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.Refilterable import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects @@ -287,6 +291,36 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { httpMaxCacheEntries: resolver.httpMetadataResolverAttributes?.httpMaxCacheEntries, httpMaxCacheEntrySize: resolver.httpMetadataResolverAttributes?.httpMaxCacheEntrySize) { + switch (MetadataRequestURLConstructionScheme.SchemeType.get(resolver.metadataRequestURLConstructionScheme.type)) { + case MetadataRequestURLConstructionScheme.SchemeType.METADATA_QUERY_PROTOCOL: + MetadataQueryProtocolScheme scheme = (MetadataQueryProtocolScheme) resolver.metadataRequestURLConstructionScheme + MetadataQueryProtocol(transformRef: scheme.transformRef) { + if (scheme.content != null) { + mkp.yield(scheme.content) + } + } + break + case MetadataRequestURLConstructionScheme.SchemeType.TEMPLATE: + TemplateScheme scheme = (TemplateScheme) resolver.metadataRequestURLConstructionScheme + Template(encodingStyle: scheme.encodingStyle, + transformRef: scheme.transformRef, + velocityEngine: scheme.velocityEngine) { + if (scheme.content != null) { + mkp.yield(scheme.content) + } + } + break + case MetadataRequestURLConstructionScheme.SchemeType.REGEX: + RegexScheme scheme = (RegexScheme) resolver.metadataRequestURLConstructionScheme + Regex(match: scheme.match) { + if (scheme.content != null) { + mkp.yield(scheme.content) + } + } + break + default: + break + } childNodes() } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/DynamicHttpMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/DynamicHttpMetadataResolver.java index d1b3692d2..b98d4188b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/DynamicHttpMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/DynamicHttpMetadataResolver.java @@ -5,9 +5,11 @@ import lombok.Setter; import lombok.ToString; +import javax.persistence.CascadeType; import javax.persistence.ElementCollection; import javax.persistence.Embedded; import javax.persistence.Entity; +import javax.persistence.OneToOne; import javax.persistence.OrderColumn; import java.util.List; @@ -36,6 +38,9 @@ public class DynamicHttpMetadataResolver extends MetadataResolver { @OrderColumn private List supportedContentTypes; + @OneToOne(cascade = CascadeType.ALL) + private MetadataRequestURLConstructionScheme metadataRequestURLConstructionScheme; + public DynamicHttpMetadataResolver() { type = "DynamicHttpMetadataResolver"; this.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataQueryProtocolScheme.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataQueryProtocolScheme.java new file mode 100644 index 000000000..cc6dffb98 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataQueryProtocolScheme.java @@ -0,0 +1,23 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +public class MetadataQueryProtocolScheme extends MetadataRequestURLConstructionScheme { + + public MetadataQueryProtocolScheme() { + type = "MetadataQueryProtocol"; + } + + private String transformRef; +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataRequestURLConstructionScheme.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataRequestURLConstructionScheme.java new file mode 100644 index 000000000..adddcc5aa --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataRequestURLConstructionScheme.java @@ -0,0 +1,61 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.persistence.Transient; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "@type", visible = true) +@JsonSubTypes({@JsonSubTypes.Type(value=MetadataQueryProtocolScheme.class, name="MetadataQueryProtocol"), + @JsonSubTypes.Type(value=TemplateScheme.class, name="Template"), + @JsonSubTypes.Type(value=RegexScheme.class, name="Regex")}) +public abstract class MetadataRequestURLConstructionScheme extends AbstractAuditable { + public enum SchemeType { + METADATA_QUERY_PROTOCOL("MetadataQueryProtocol"), + TEMPLATE("Template"), + REGEX("Regex"); + + private String schemeType; + private static final Map lookup = new HashMap<>(); + + static { + for (SchemeType schemeType : SchemeType.values()) { + lookup.put(schemeType.toString(), schemeType); + } + } + + SchemeType(String schemeType) { + this.schemeType = schemeType; + } + + public static SchemeType get(String schemeType) { + return lookup.get(schemeType); + } + + @Override + public String toString() { + return schemeType; + } + } + + @JsonProperty("@type") + @Transient + String type; + + String content; +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/RegexScheme.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/RegexScheme.java new file mode 100644 index 000000000..bb175432c --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/RegexScheme.java @@ -0,0 +1,25 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; +import javax.validation.constraints.NotNull; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +public class RegexScheme extends MetadataRequestURLConstructionScheme { + + public RegexScheme() { + type = "Regex"; + } + + @NotNull + private String match; +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/TemplateScheme.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/TemplateScheme.java new file mode 100644 index 000000000..6cb0c8d90 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/TemplateScheme.java @@ -0,0 +1,31 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Entity; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +public class TemplateScheme extends MetadataRequestURLConstructionScheme { + + public TemplateScheme () { + type = "Template"; + } + + public enum EncodingStyle { + NONE, FORM, PATH, FRAGMENT + } + + private EncodingStyle encodingStyle = EncodingStyle.FORM; + + private String transformRef; + + private String velocityEngine = "shibboleth.VelocityEngine"; +} diff --git a/backend/src/main/resources/dynamic-http-metadata-provider.schema.json b/backend/src/main/resources/dynamic-http-metadata-provider.schema.json index 231078877..4e7a52786 100644 --- a/backend/src/main/resources/dynamic-http-metadata-provider.schema.json +++ b/backend/src/main/resources/dynamic-http-metadata-provider.schema.json @@ -22,12 +22,114 @@ "default": "", "minLength": 1 }, - "metadataURL": { - "title": "label.metadata-url", - "description": "tooltip.metadata-url", - "type": "string", - "default": "", - "minLength": 1 + "metadataRequestURLConstructionScheme": { + "type": "object", + "properties": { + "@type": { + "title": "label.md-request-type", + "description": "tooltip.md-request-type", + "type": "string", + "widget": { + "id": "select" + }, + "oneOf": [ + { + "enum": [ + "MetadataQueryProtocol" + ], + "description": "value.md-query-protocol" + }, + { + "enum": [ + "Template" + ], + "description": "value.template" + }, + { + "enum": [ + "Regex" + ], + "description": "value.regex" + } + ] + }, + "content": { + "title": "label.md-request-value", + "description": "tooltip.md-request-value", + "type": "string" + }, + "transformRef": { + "title": "label.transform-ref", + "description": "tooltip.transform-ref", + "type": "string", + "visibleIf": { + "content": [ + "" + ] + } + }, + "encodingStyle": { + "title": "label.encoding-style", + "description": "tooltip.encoding-style", + "type": "string", + "widget": { + "id": "select" + }, + "default": "FORM", + "oneOf": [ + { + "enum": [ + "NONE" + ], + "description": "None" + }, + { + "enum": [ + "FORM" + ], + "description": "Form" + }, + { + "enum": [ + "PATH" + ], + "description": "Path" + }, + { + "enum": [ + "FRAGMENT" + ], + "description": "Fragment" + } + ], + "visibleIf": { + "@type": [ + "Template" + ] + } + }, + "velocityEngine": { + "title": "label.velocity-engine", + "description": "tooltip.velocity-engine", + "type": "string", + "default": "shibboleth.VelocityEngine", + "visibleIf": { + "@type": [ + "Template" + ] + } + }, + "match": { + "title": "label.match", + "description": "tooltip.match", + "type": "string", + "visibleIf": { + "@type": [ + "Regex" + ] + } + } + } }, "requireValidMetadata": { "title": "label.require-valid-metadata", diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 87aaf7299..31c4de9b8 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -76,6 +76,11 @@ value.dynamic-http-metadata-provider=DynamicHttpMetadataProvider value.entity-attributes-filter=EntityAttributes Filter value.spdescriptor=SPSSODescriptor value.attr-auth-descriptor=AttributeAuthorityDescriptor +value.dynamic-http-metadata-provider=DynamicHttpMetadataProvider +value.local-dynamic-metadata-provider=LocalDynamicMetadataProvider + +value.md-query-protocol=MetadataQueryProtocol +value.template=Template brand.header.title=Source Management brand.logo-link-label=Shibboleth @@ -218,6 +223,7 @@ label.entity-id=Entity ID label.service-provider-name=Service Provider Name label.organization=Organization label.contacts=Contacts +label.contact=Contact label.mdui=MDUI Information label.service-provider-sso-descriptor=Service Provider Sso Descriptor label.service-enabled=Service Enabled @@ -316,6 +322,7 @@ label.reloading-attributes=Reloading Attributes label.metadata-filter-plugins=Metadata Filter Plugins label.advanced-settings=Advanced Settings label.edit-metadata-provider=Edit Metadata Provider +label.http-settings-advanced=Http Settings (Advanced) label.metadata-ui=User Interface / MDUI Information label.descriptor-info=SP SSO Descriptor Information @@ -337,9 +344,27 @@ label.attribute-eduPersonUniqueId=eduPersonUniqueId label.attribute-employeeNumber=employeeNumber label.force-authn=Force AuthN +label.dynamic-attributes=Dynamic Attributes +label.min-cache-duration=Min Cache Duration +label.max-cache-duration=Max Cache Duration +label.max-idle-entity-data=Max Idle Entity Data +label.cleanup-task-interval=Cleanup Task Interval +label.persistent-cache-manager-directory=Persistent Cache Manager Directory +label.initialize-from-persistent-cache-in-background=Initialize from Persistent Cache in Background? +label.background-init-from-cache-delay=Background Initialization from Cache Delay +label.source-directory=Source Directory +label.remove-idle-entity-data=Remove Idle Entity Data? label.do-resolver-initialization=Initialize label.file-doesnt-exist=The file specified in the resolver does not exist on the file system. Therefore, the resolver cannot be initialized. +label.md-request-type=Metadata Request URL Construction Type +label.md-request-value=Metadata Request URL Construction Value +label.transform-ref=Transform Ref +label.encoding-style=Encoding Style +label.velocity-engine=Velocity Engine +label.match=Match + + message.must-be-unique=Must be unique. message.name-must-be-unique=Name must be unique. message.uri-valid-format=URI must be valid format. @@ -436,6 +461,7 @@ tooltip.metadata-provider-name=Metadata Provider Name tooltip.metadata-provider-type=Metadata Provider Type tooltip.xml-id=Identifier for logging, identification for command line reload, etc. tooltip.metadata-url=Identifier for logging, identification for command line reload, etc. +tooltip.metadata-file=The absolute path to the local metadata file to be loaded. tooltip.init-from-backup=Flag indicating whether initialization should first attempt to load metadata from the backup file. If true, foreground initialization will be performed by loading the backing file, and then a refresh from the remote HTTP server will be scheduled to execute in a background thread, after a configured delay. This can improve IdP startup times when the remote HTTP file is large in size. tooltip.backing-file=Specifies where the backing file is located. If the remote server is unavailable at startup, the backing file is loaded instead. tooltip.backup-file-init-refresh-delay=Delay duration after which to schedule next HTTP refresh when initialized from the backing file. @@ -462,4 +488,21 @@ tooltip.filter-name=Filter Name tooltip.enable-filter=Enable Filter? tooltip.enable-service=Enable Service? +tooltip.min-cache-duration=The minimum duration for which metadata will be cached before it is refreshed. +tooltip.max-cache-duration=The maximum duration for which metadata will be cached before it is refreshed. +tooltip.max-idle-entity-data=The maximum duration for which metadata will be allowed to be idle (no requests for it) before it is removed from the cache. +tooltip.cleanup-task-interval=The interval at which the internal cleanup task should run. This task performs background maintenance tasks, such as the removal of expired and idle metadata. +tooltip.persistent-cache-manager-directory=The optional manager for the persistent cache store for resolved metadata. On metadata provider initialization, data present in the persistent cache will be loaded to memory, effectively restoring the state of the provider as closely as possible to that which existed before the previous shutdown. Each individual cache entry will only be loaded if 1) the entry is still valid as determined by the internal provider logic, and 2) the entry passes the (optional) predicate supplied via initializationFromCachePredicateRef. +tooltip.initialize-from-persistent-cache-in-background=Flag indicating whether should initialize from the persistent cache in the background. Initializing from the cache in the background will improve IdP startup times. +tooltip.background-init-from-cache-delay=The delay after which to schedule the background initialization from the persistent cache when initializeFromPersistentCacheInBackground=true. + +tooltip.source-directory=Convenience mechanism for wiring a FilesystemLoadSaveManager, loading from the specified source directory in the local filesystem. This attribute will be ignored if sourceManagerRef is also specified. Either this attribute or sourceManagerRef is required. +tooltip.remove-idle-entity-data=Flag indicating whether idle metadata should be removed. + tooltip.do-resolver-initialization=Initialize this resolver? In the case of Filesystem resolvers, this will cause the system to read the file and index the resolver. +tooltip.md-request-type=Options are 1) Metadata Query Protocol, 2) Template, 3) Regex. +tooltip.md-request-value=Content of the element. +tooltip.transform-ref=A reference to a transform function for the entityID. If used, the child element must be empty. +tooltip.encoding-style=Determines whether and how the entityID value will be URL encoded prior to replacement. Allowed values are: 1) "none" - no encoding is performed, 2) "form" - encoded using URL form parameter encoding (for query parameters), 3) "path" - encoded using URL path encoding, or 4) "fragment" - encoded using URL fragment encoding. The precise definition of these terms is defined in the documentation for the methods of the Guava library\u0027s UrlEscapers class. +tooltip.velocity-engine=This attribute may be used to specify the name of the Velocity engine defined within the application. +tooltip.match=A regular expression against which the entityID is evaluated. \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index ed8313f38..31c4de9b8 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -79,6 +79,9 @@ value.attr-auth-descriptor=AttributeAuthorityDescriptor value.dynamic-http-metadata-provider=DynamicHttpMetadataProvider value.local-dynamic-metadata-provider=LocalDynamicMetadataProvider +value.md-query-protocol=MetadataQueryProtocol +value.template=Template + brand.header.title=Source Management brand.logo-link-label=Shibboleth brand.logo-link-description=Link to Shibboleth Website @@ -354,6 +357,14 @@ label.remove-idle-entity-data=Remove Idle Entity Data? label.do-resolver-initialization=Initialize label.file-doesnt-exist=The file specified in the resolver does not exist on the file system. Therefore, the resolver cannot be initialized. +label.md-request-type=Metadata Request URL Construction Type +label.md-request-value=Metadata Request URL Construction Value +label.transform-ref=Transform Ref +label.encoding-style=Encoding Style +label.velocity-engine=Velocity Engine +label.match=Match + + message.must-be-unique=Must be unique. message.name-must-be-unique=Name must be unique. message.uri-valid-format=URI must be valid format. @@ -489,3 +500,9 @@ tooltip.source-directory=Convenience mechanism for wiring a FilesystemLoadSaveMa tooltip.remove-idle-entity-data=Flag indicating whether idle metadata should be removed. tooltip.do-resolver-initialization=Initialize this resolver? In the case of Filesystem resolvers, this will cause the system to read the file and index the resolver. +tooltip.md-request-type=Options are 1) Metadata Query Protocol, 2) Template, 3) Regex. +tooltip.md-request-value=Content of the element. +tooltip.transform-ref=A reference to a transform function for the entityID. If used, the child element must be empty. +tooltip.encoding-style=Determines whether and how the entityID value will be URL encoded prior to replacement. Allowed values are: 1) "none" - no encoding is performed, 2) "form" - encoded using URL form parameter encoding (for query parameters), 3) "path" - encoded using URL path encoding, or 4) "fragment" - encoded using URL fragment encoding. The precise definition of these terms is defined in the documentation for the methods of the Guava library\u0027s UrlEscapers class. +tooltip.velocity-engine=This attribute may be used to specify the name of the Velocity engine defined within the application. +tooltip.match=A regular expression against which the entityID is evaluated. \ No newline at end of file diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy index cae0c8afc..19c0fb5e3 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/IncommonJPAMetadataResolverServiceImplTests.groovy @@ -57,8 +57,6 @@ class IncommonJPAMetadataResolverServiceImplTests extends Specification { metadataResolverRepository.save(mr) def output = metadataResolverService.generateConfiguration() - println(output.documentElement) - then: generatedXmlIsTheSameAsExpectedXml('/conf/278.xml', output) } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy index 8bb9bc7d4..1e2e61b3c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/JPAMetadataResolverServiceImplTests.groovy @@ -9,7 +9,11 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFil import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget import edu.internet2.tier.shibboleth.admin.ui.domain.filters.RequiredValidUntilFilter import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ClasspathMetadataResource +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataQueryProtocolScheme +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.RegexScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.SvnMetadataResource +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.TemplateScheme import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository @@ -280,6 +284,71 @@ class JPAMetadataResolverServiceImplTests extends Specification { generatedXmlIsTheSameAsExpectedXml('/conf/670.xml', generatedXmlDocument) } + def 'test generating DynamicHttpMetadataResolver xml snippet with MetadataQueryProtocolScheme'() { + given: + def resolver = new DynamicHttpMetadataResolver().with { + it.xmlId = 'DynamicHttpMetadataResolver' + it.metadataRequestURLConstructionScheme = new MetadataQueryProtocolScheme().with { + it.transformRef = 'This is a transformRef' + it.content = 'some content' + it + } + it + } + + when: + genXmlSnippet(markupBuilder) { + JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForResolver(resolver, it) {} + } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/704.1.xml', domBuilder.parseText(writer.toString())) + } + + def 'test generating DynamicHttpMetadataResolver xml snippet with TemplateScheme'() { + given: + def resolver = new DynamicHttpMetadataResolver().with { + it.xmlId = 'DynamicHttpMetadataResolver' + it.metadataRequestURLConstructionScheme = new TemplateScheme().with { + it.encodingStyle = TemplateScheme.EncodingStyle.FORM + it.transformRef = 'This is a transformRef' + it.velocityEngine = 'This is a velocityEngine' + it.content = 'some content' + it + } + it + } + + when: + genXmlSnippet(markupBuilder) { + JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForResolver(resolver, it) {} + } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/704.2.xml', domBuilder.parseText(writer.toString())) + } + + def 'test generating DynamicHttpMetadataResolver xml snippet with RegexScheme'() { + given: + def resolver = new DynamicHttpMetadataResolver().with { + it.xmlId = 'DynamicHttpMetadataResolver' + it.metadataRequestURLConstructionScheme = new RegexScheme().with { + it.match = 'This is the match field' + it.content = 'some content' + it + } + it + } + + when: + genXmlSnippet(markupBuilder) { + JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForResolver(resolver, it) {} + } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/704.3.xml', domBuilder.parseText(writer.toString())) + } + static genXmlSnippet(MarkupBuilder xml, Closure xmlNodeGenerator) { xml.MetadataProvider('id': 'ShibbolethMetadata', 'xmlns': 'urn:mace:shibboleth:2.0:metadata', diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy index eaf031c3e..071516cc2 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy @@ -512,6 +512,11 @@ class TestObjectGenerator { it.dynamicMetadataResolverAttributes = new DynamicMetadataResolverAttributes().with { it } + it.metadataRequestURLConstructionScheme = new MetadataQueryProtocolScheme().with { + it.transformRef = 'transformRef' + it.content = 'content' + it + } it } } diff --git a/backend/src/test/resources/conf/278.2.xml b/backend/src/test/resources/conf/278.2.xml index 269a2f3ec..b6c1d0d89 100644 --- a/backend/src/test/resources/conf/278.2.xml +++ b/backend/src/test/resources/conf/278.2.xml @@ -23,6 +23,7 @@ socketTimeout="PT5S" supportedContentTypes="[]" xsi:type="DynamicHttpMetadataProvider"> + content diff --git a/backend/src/test/resources/conf/278.xml b/backend/src/test/resources/conf/278.xml index 3bebc347b..6db6e5cfa 100644 --- a/backend/src/test/resources/conf/278.xml +++ b/backend/src/test/resources/conf/278.xml @@ -23,6 +23,7 @@ socketTimeout="PT5S" supportedContentTypes="[]" xsi:type="DynamicHttpMetadataProvider"> + content diff --git a/backend/src/test/resources/conf/704.1.xml b/backend/src/test/resources/conf/704.1.xml new file mode 100644 index 000000000..a7e5d63a0 --- /dev/null +++ b/backend/src/test/resources/conf/704.1.xml @@ -0,0 +1,5 @@ + + + some content + + \ No newline at end of file diff --git a/backend/src/test/resources/conf/704.2.xml b/backend/src/test/resources/conf/704.2.xml new file mode 100644 index 000000000..823b89de4 --- /dev/null +++ b/backend/src/test/resources/conf/704.2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/backend/src/test/resources/conf/704.3.xml b/backend/src/test/resources/conf/704.3.xml new file mode 100644 index 000000000..d7ce637d3 --- /dev/null +++ b/backend/src/test/resources/conf/704.3.xml @@ -0,0 +1,5 @@ + + + some content + + \ No newline at end of file diff --git a/ui/src/app/metadata/provider/container/provider-wizard-step.component.html b/ui/src/app/metadata/provider/container/provider-wizard-step.component.html index 5d07730fd..a9a3be2e4 100644 --- a/ui/src/app/metadata/provider/container/provider-wizard-step.component.html +++ b/ui/src/app/metadata/provider/container/provider-wizard-step.component.html @@ -3,6 +3,7 @@ [schema]="schema$ | async" [model]="model$ | async" [validators]="validators$ | async" + [bindings]="bindings$ | async" (onChange)="valueChangeSubject.next($event)" (onErrorChange)="statusChangeSubject.next($event)"> \ No newline at end of file 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 9ff4ded23..a0b145078 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 @@ -28,6 +28,7 @@ export class ProviderWizardStepComponent implements OnDestroy { private statusChangeEmitted$ = this.statusChangeSubject.asObservable(); schema$: Observable; + bindings$: Observable; schema: any; definition$: Observable>; changes$: Observable; @@ -46,6 +47,7 @@ export class ProviderWizardStepComponent implements OnDestroy { filter(s => s && Object.keys(s.properties).length > 0) ); this.definition$ = this.store.select(fromWizard.getWizardDefinition); + this.bindings$ = this.definition$.pipe(map(d => d.bindings)); this.changes$ = this.store.select(fromProvider.getEntityChanges); this.validators$ = this.definition$.pipe( 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 1cfcb7073..9499d19c0 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 @@ -1,3 +1,7 @@ +import { FormProperty } from 'ngx-schema-form/lib/model/formproperty'; +import { ArrayProperty } from 'ngx-schema-form/lib/model/arrayproperty'; +import { ObjectProperty } from 'ngx-schema-form/lib/model/objectproperty'; + import { Wizard } from '../../../wizard/model'; import { DynamicHttpMetadataProvider } from '../../domain/model/providers/dynamic-http-metadata-provider'; import { BaseMetadataProviderEditor } from './base.provider.form'; @@ -7,6 +11,21 @@ export const DynamicHttpMetadataProviderWizard: Wizard { + let transform = property.parent.getProperty('transformRef'); + let content = property.parent.getProperty('content'); + if (!content.value && property.value !== 'Regex') { + transform.setVisible(true); + } else { + transform.setVisible(false); + } + } + } + ] + }, getValidators(namesList: string[] = [], xmlIdList: string[] = []): any { const validators = BaseMetadataProviderEditor.getValidators(namesList); validators['/xmlId'] = (value, property, form) => { @@ -35,13 +54,13 @@ export const DynamicHttpMetadataProviderWizard: Wizard