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 64f33a01d..f094ff2f9 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 @@ -5,6 +5,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.* import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import groovy.util.logging.Slf4j @@ -22,6 +23,9 @@ import org.opensaml.saml.saml2.metadata.EntityDescriptor import org.springframework.beans.factory.annotation.Autowired import org.w3c.dom.Document +import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.CLASSPATH +import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.SVN + @Slf4j class JPAMetadataResolverServiceImpl implements MetadataResolverService { @@ -272,4 +276,49 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { childNodes() } } + + void constructXmlNodeForResolver(ResourceBackedMetadataResolver resolver, def markupBuilderDelegate, Closure childNodes) { + //This might throw an InvalidResourceTypeException if both resource types do not satisfy validation rules + //But this validation step already would have been performed by higher app layers such as REST controllers, + //and if this is not done, an exception thrown here would be trully considered a server side error bug which would + //need to be taken care of + def resourceType = resolver.validateAndDetermineResourceType() + + markupBuilderDelegate.MetadataProvider( + id: resolver.name, + 'xsi:type': 'ResourceBackedMetadataProvider', + parserPoolRef: resolver.reloadableMetadataResolverAttributes?.parserPoolRef, + minRefreshDelay: resolver.reloadableMetadataResolverAttributes?.minRefreshDelay, + maxRefreshDelay: resolver.reloadableMetadataResolverAttributes?.maxRefreshDelay, + refreshDelayFactor: resolver.reloadableMetadataResolverAttributes?.refreshDelayFactor, + indexesRef: resolver.reloadableMetadataResolverAttributes?.indexesRef, + resolveViaPredicatesOnly: resolver.reloadableMetadataResolverAttributes?.resolveViaPredicatesOnly ?: null, + expirationWarningThreshold: resolver.reloadableMetadataResolverAttributes?.expirationWarningThreshold) { + + if(resourceType == SVN) { + MetadataResource( + 'xmlns:resource': 'urn:mace:shibboleth:2.0:resource', + 'xsi:type': 'resource:SVNResource', + 'resourceFile': resolver.svnMetadataResource.resourceFile, + 'repositoryURL': resolver.svnMetadataResource.repositoryURL, + 'workingCopyDirectory': resolver.svnMetadataResource.workingCopyDirectory, + 'username': resolver.svnMetadataResource.username, + 'password': resolver.svnMetadataResource.password, + 'proxyHost': resolver.svnMetadataResource.proxyHost, + 'proxyPort': resolver.svnMetadataResource.proxyHost, + 'proxyUserName': resolver.svnMetadataResource.proxyUserName, + 'proxyPassword': resolver.svnMetadataResource.proxyPassword) + + } + else if (resourceType == CLASSPATH) { + MetadataResource( + 'xmlns:resource': 'urn:mace:shibboleth:2.0:resource', + 'xsi:type': 'resource:ClasspathResource', + 'file': resolver.classpathMetadataResource.file) + } + + childNodes() + } + + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java index bbb41d357..6e60ebf5b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java @@ -1,6 +1,5 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -8,7 +7,6 @@ import javax.persistence.Embedded; import javax.persistence.Entity; -import javax.persistence.Transient; import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.CLASSPATH; import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.SVN; 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 4e4600ae9..24a97ccdb 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 @@ -19,7 +19,6 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @@ -31,7 +30,6 @@ import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.* @ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class IncommonJPAMetadataResolverServiceImplTests extends Specification { @Autowired MetadataResolverService metadataResolverService @@ -42,6 +40,10 @@ class IncommonJPAMetadataResolverServiceImplTests extends Specification { @Autowired AttributeUtility attributeUtility + def cleanup() { + metadataResolverRepository.deleteAll() + } + def 'simple test generation of metadata-providers.xml'() { when: def mr = metadataResolverRepository.findAll().iterator().next() @@ -137,6 +139,9 @@ class IncommonJPAMetadataResolverServiceImplTests extends Specification { // Generate and test edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver. metadataResolverRepository.save(new TestObjectGenerator(attributeUtility).localDynamicMetadataResolver()) + + // Generate and test edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver + metadataResolverRepository.save(new TestObjectGenerator(attributeUtility).resourceBackedMetadataResolverForSVN()) } return resolver 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 e548d26b5..59a980423 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 @@ -5,6 +5,8 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter 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.SvnMetadataResource import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository @@ -42,7 +44,6 @@ import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedX @ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) class JPAMetadataResolverServiceImplTests extends Specification { @Autowired MetadataResolverRepository metadataResolverRepository @@ -80,6 +81,7 @@ class JPAMetadataResolverServiceImplTests extends Specification { } def cleanup() { + metadataResolverRepository.deleteAll() writer.close() } @@ -170,6 +172,48 @@ class JPAMetadataResolverServiceImplTests extends Specification { generatedXmlIsTheSameAsExpectedXml('/conf/532.xml', domBuilder.parseText(writer.toString())) } + def 'test generating ResourceBackedMetadataResolver with SVN resource type xml snippet'() { + given: + def resolver = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver().with { + it.name = 'SVNResourceMetadata' + it.svnMetadataResource = new SvnMetadataResource().with { + it.resourceFile = 'entity.xml' + it.repositoryURL = 'https://svn.example.org/repo/path/to.dir' + it.workingCopyDirectory = '%{idp.home}/metadata/svn' + it + } + it + } + + when: + genXmlSnippet(markupBuilder) { + JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForResolver(resolver, it) {} + } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/546-svn.xml', domBuilder.parseText(writer.toString())) + } + + def 'test generating ResourceBackedMetadataResolver with classpath resource type xml snippet'() { + given: + def resolver = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver().with { + it.name = 'ClasspathResourceMetadata' + it.classpathMetadataResource = new ClasspathMetadataResource().with { + it.file = '/path/to/a/classpath/location/metadata.xml' + it + } + it + } + + when: + genXmlSnippet(markupBuilder) { + JPAMetadataResolverServiceImpl.cast(metadataResolverService).constructXmlNodeForResolver(resolver, it) {} + } + + then: + generatedXmlIsTheSameAsExpectedXml('/conf/546-classpath.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 fe5be3277..77e96e82d 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 @@ -406,6 +406,19 @@ class TestObjectGenerator { } } + ResourceBackedMetadataResolver resourceBackedMetadataResolverForSVN() { + new ResourceBackedMetadataResolver().with { + it.name = 'SVNResourceMetadata' + it.svnMetadataResource = new SvnMetadataResource().with { + it.resourceFile = 'entity.xml' + it.repositoryURL = 'https://svn.example.org/repo/path/to.dir' + it.workingCopyDirectory = '%{idp.home}/metadata/svn' + it + } + it + } + } + FileBackedHttpMetadataResolver buildFileBackedHttpMetadataResolver() { def resolver = new FileBackedHttpMetadataResolver() resolver.name = generator.randomString(10) diff --git a/backend/src/test/resources/conf/278.2.xml b/backend/src/test/resources/conf/278.2.xml index bd6c3b082..216f9626c 100644 --- a/backend/src/test/resources/conf/278.2.xml +++ b/backend/src/test/resources/conf/278.2.xml @@ -52,5 +52,13 @@ xsi:type="DynamicHttpMetadataProvider"> + + + + \ No newline at end of file diff --git a/backend/src/test/resources/conf/278.xml b/backend/src/test/resources/conf/278.xml index 7241943ab..6f845bf59 100644 --- a/backend/src/test/resources/conf/278.xml +++ b/backend/src/test/resources/conf/278.xml @@ -45,4 +45,12 @@ xsi:type="DynamicHttpMetadataProvider"> + + + + \ No newline at end of file diff --git a/backend/src/test/resources/conf/546-classpath.xml b/backend/src/test/resources/conf/546-classpath.xml new file mode 100644 index 000000000..13cba309c --- /dev/null +++ b/backend/src/test/resources/conf/546-classpath.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/backend/src/test/resources/conf/546-svn.xml b/backend/src/test/resources/conf/546-svn.xml new file mode 100644 index 000000000..579c7dc78 --- /dev/null +++ b/backend/src/test/resources/conf/546-svn.xml @@ -0,0 +1,16 @@ + + + + + + + +