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 a4a8451fd..f8eb32a38 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 @@ -11,18 +11,16 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMet 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.ResourceBackedMetadataResolver +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 import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import groovy.util.logging.Slf4j import groovy.xml.DOMBuilder import groovy.xml.MarkupBuilder -import net.shibboleth.utilities.java.support.logic.ScriptedPredicate -import net.shibboleth.utilities.java.support.resolver.ResolverException import net.shibboleth.utilities.java.support.scripting.EvaluableScript import org.opensaml.saml.common.profile.logic.EntityIdPredicate -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver -import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver import org.opensaml.saml.metadata.resolver.filter.MetadataFilter import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain import org.opensaml.saml.saml2.core.Attribute @@ -52,10 +50,10 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { // TODO: enhance @Override - void reloadFilters(String metadataResolverName) { - ChainingMetadataResolver chainingMetadataResolver = (ChainingMetadataResolver) metadataResolver - MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { it.id == metadataResolverName } - edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByName(metadataResolverName) + void reloadFilters(String metadataResolverResourceId) { + OpenSamlChainingMetadataResolver chainingMetadataResolver = (OpenSamlChainingMetadataResolver) metadataResolver + MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { it.id == metadataResolverResourceId } + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByResourceId(metadataResolverResourceId) if (targetMetadataResolver && targetMetadataResolver.getMetadataFilter() instanceof MetadataFilterChain) { MetadataFilterChain metadataFilterChain = (MetadataFilterChain) targetMetadataResolver.getMetadataFilter() @@ -94,12 +92,11 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService { metadataFilterChain.setFilters(metadataFilters) } - if (metadataResolver instanceof RefreshableMetadataResolver) { - try { - ((RefreshableMetadataResolver) metadataResolver).refresh() - } catch (ResolverException e) { - log.warn("error refreshing metadataResolver " + metadataResolverName, e) - } + if (targetMetadataResolver != null && targetMetadataResolver instanceof Refilterable) { + (Refilterable) targetMetadataResolver.refilter() + } else { + //TODO: Do something here if we need to refilter other non-Batch resolvers + log.warn("Target resolver is not a Refilterable resolver. Skipping refilter()") } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java new file mode 100644 index 000000000..6380e0018 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConverterConfiguration.java @@ -0,0 +1,17 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration; + +import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService; +import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterServiceImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Configuration +public class MetadataResolverConverterConfiguration { + @Bean + public MetadataResolverConverterService metadataResolverConverterService() { + return new MetadataResolverConverterServiceImpl(); + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java index 632809bea..431632023 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersController.java @@ -88,8 +88,7 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques MetadataResolver persistedMr = repository.save(metadataResolver); // we reload the filters here after save - metadataResolverService.reloadFilters(persistedMr.getName()); - refreshOrInitResolver(metadataResolver); + metadataResolverService.reloadFilters(persistedMr.getResourceId()); MetadataFilter persistedFilter = newlyPersistedFilter(persistedMr.getMetadataFilters().stream(), createdFilter.getResourceId()); @@ -98,33 +97,6 @@ public ResponseEntity create(@PathVariable String metadataResolverId, @Reques .body(persistedFilter); } - private void refreshOrInitResolver(MetadataResolver resolver) { - List resolvers = ((ChainingMetadataResolver) chainingMetadataResolver).getResolvers(); - resolvers.stream().filter(it -> it.getId().equals(resolver.getResourceId())).forEach(it -> { - if (it instanceof RefreshableMetadataResolver) { - try { - ((RefreshableMetadataResolver) it).refresh(); - } catch (ResolverException e) { - //TODO what should we do if we can't refresh? - } - } else if (it instanceof OpenSamlFunctionDrivenDynamicHTTPMetadataResolver) { - try { - ((OpenSamlFunctionDrivenDynamicHTTPMetadataResolver) it).refresh(); - } catch (ComponentInitializationException e) { - //TODO what should we do if we can't refresh? - } - } else if (it instanceof OpenSamlLocalDynamicMetadataResolver) { - try { - ((OpenSamlLocalDynamicMetadataResolver) it).refresh(); - } catch (ComponentInitializationException e) { - //TODO what should we do if we can't refresh? - } - } else { - //TODO we shouldn't get here, but if we do... throw exception? - } - }); - } - @PutMapping("/Filters/{resourceId}") public ResponseEntity update(@PathVariable String metadataResolverId, @PathVariable String resourceId, @@ -158,8 +130,7 @@ public ResponseEntity update(@PathVariable String metadataResolverId, MetadataFilter persistedFilter = filterRepository.save(filterTobeUpdated); // TODO: this is wrong - metadataResolverService.reloadFilters(metadataResolver.getName()); - refreshOrInitResolver(metadataResolver); + metadataResolverService.reloadFilters(metadataResolver.getResourceId()); return ResponseEntity.ok().body(persistedFilter); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java index 4d7d7aaac..47458273d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java @@ -3,15 +3,16 @@ import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidationService; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService; import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolversPositionOrderContainerService; +import edu.internet2.tier.shibboleth.admin.util.OpenSamlChainingMetadataResolverUtil; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -36,7 +37,6 @@ import java.io.IOException; import java.io.StringWriter; import java.net.URI; -import java.util.ArrayList; import java.util.List; import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator.ValidationResult; @@ -118,19 +118,14 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) throw MetadataResolver persistedResolver = resolverRepository.save(newResolver); positionOrderContainerService.appendPositionOrderForNew(persistedResolver); - updateChainingMetadataResolver(persistedResolver); + //TODO: currently, the update call might explode, but the save works.. in which case, the UI never gets + // n valid response. This operation is not atomic. Should we return an error here? + org.opensaml.saml.metadata.resolver.MetadataResolver openSamlRepresentation = metadataResolverConverterService.convertToOpenSamlRepresentation(persistedResolver); + OpenSamlChainingMetadataResolverUtil.updateChainingMetadataResolver((OpenSamlChainingMetadataResolver) chainingMetadataResolver, openSamlRepresentation); return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } - private void updateChainingMetadataResolver(MetadataResolver persistedResolver) throws IOException, ResolverException, ComponentInitializationException { - org.opensaml.saml.metadata.resolver.MetadataResolver openSamlResolver = metadataResolverConverterService.convertToOpenSamlRepresentation(persistedResolver); - List resolverList = new ArrayList<>(((ChainingMetadataResolver) chainingMetadataResolver).getResolvers()); - resolverList.removeIf(resolver -> resolver.getId().equals(persistedResolver.getResourceId())); - resolverList.add(openSamlResolver); - ((ChainingMetadataResolver) chainingMetadataResolver).setResolvers(resolverList); - } - @PutMapping("/MetadataResolvers/{resourceId}") @Transactional public ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) throws IOException, ResolverException, ComponentInitializationException { @@ -153,7 +148,8 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); - updateChainingMetadataResolver(persistedResolver); + org.opensaml.saml.metadata.resolver.MetadataResolver openSamlRepresentation = metadataResolverConverterService.convertToOpenSamlRepresentation(persistedResolver); + OpenSamlChainingMetadataResolverUtil.updateChainingMetadataResolver((OpenSamlChainingMetadataResolver) chainingMetadataResolver, openSamlRepresentation); return ResponseEntity.ok(persistedResolver); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlChainingMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlChainingMetadataResolver.java index cfea6d89c..3213736a6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlChainingMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlChainingMetadataResolver.java @@ -29,7 +29,7 @@ public class OpenSamlChainingMetadataResolver extends ChainingMetadataResolver { @Nonnull @NonnullElements private List mutableResolvers; public OpenSamlChainingMetadataResolver() { - this.mutableResolvers = Collections.emptyList(); + this.mutableResolvers = new ArrayList<>(); } public OpenSamlChainingMetadataResolver(@Nonnull List mutableResolvers) { @@ -39,7 +39,7 @@ public OpenSamlChainingMetadataResolver(@Nonnull List mutableR @Override public void setResolvers(@Nonnull @NonnullElements final List newResolvers) { if (newResolvers == null || newResolvers.isEmpty()) { - mutableResolvers = Collections.emptyList(); + mutableResolvers = new ArrayList<>(); return; } @@ -78,7 +78,7 @@ protected void doInitialize() throws ComponentInitializationException { super.doInitialize(); if (mutableResolvers == null) { log.warn("OpenSamlChainingMetadataResolver was not configured with any member MetadataResolvers"); - mutableResolvers = Collections.emptyList(); + mutableResolvers = new ArrayList<>(); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java index 04c223bc0..f1e551b8e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java @@ -8,7 +8,11 @@ import org.apache.http.impl.client.HttpClients; import org.apache.lucene.index.IndexWriter; import org.joda.time.DateTime; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain; import org.opensaml.saml.metadata.resolver.impl.FileBackedHTTPMetadataResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; @@ -18,7 +22,10 @@ /** * @author Bill Smith (wsmith@unicon.net) */ -public class OpenSamlFileBackedHTTPMetadataResolver extends FileBackedHTTPMetadataResolver { +public class OpenSamlFileBackedHTTPMetadataResolver extends FileBackedHTTPMetadataResolver implements Refilterable { + + private static final Logger logger = LoggerFactory.getLogger(OpenSamlFileBackedHTTPMetadataResolver.class); + private IndexWriter indexWriter; private FileBackedHttpMetadataResolver sourceResolver; @@ -46,6 +53,8 @@ public OpenSamlFileBackedHTTPMetadataResolver(ParserPool parserPool, this.setInitializeFromBackupFile(sourceResolver.getInitializeFromBackupFile()); + this.setMetadataFilter(new MetadataFilterChain()); + //TODO: Where does this get set in OpenSAML land? // sourceResolver.getMetadataURL(); } @@ -72,4 +81,15 @@ protected void initMetadataResolver() throws ComponentInitializationException { this.sourceResolver.getResourceId(), indexWriter); } + + /** + * {@inheritDoc} + */ + public void refilter() { + try { + this.getBackingStore().setCachedFilteredMetadata(filterMetadata(getCachedOriginalMetadata())); + } catch (FilterException e) { + logger.error("An error occurred while attempting to filter metadata!", e); + } + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFilesystemMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFilesystemMetadataResolver.java index ad3ee65d9..b4fb6d578 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFilesystemMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFilesystemMetadataResolver.java @@ -5,7 +5,11 @@ import net.shibboleth.utilities.java.support.xml.ParserPool; import org.apache.lucene.index.IndexWriter; import org.joda.time.DateTime; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain; import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.File; @@ -13,7 +17,10 @@ /** * @author Bill Smith (wsmith@unicon.net) */ -public class OpenSamlFilesystemMetadataResolver extends FilesystemMetadataResolver { +public class OpenSamlFilesystemMetadataResolver extends FilesystemMetadataResolver implements Refilterable { + + private static final Logger logger = LoggerFactory.getLogger(OpenSamlFilesystemMetadataResolver.class); + private IndexWriter indexWriter; private edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FilesystemMetadataResolver sourceResolver; private OpenSamlMetadataResolverDelegate delegate; @@ -31,6 +38,8 @@ public OpenSamlFilesystemMetadataResolver(ParserPool parserPool, OpenSamlMetadataResolverConstructorHelper.updateOpenSamlMetadataResolverFromReloadableMetadataResolverAttributes( this, sourceResolver.getReloadableMetadataResolverAttributes(), parserPool); + + this.setMetadataFilter(new MetadataFilterChain()); } // TODO: this is still probably not the best way to do this? @@ -48,4 +57,15 @@ protected void initMetadataResolver() throws ComponentInitializationException { this.sourceResolver.getResourceId(), indexWriter); } + + /** + * {@inheritDoc} + */ + public void refilter() { + try { + this.getBackingStore().setCachedFilteredMetadata(filterMetadata(getCachedOriginalMetadata())); + } catch (FilterException e) { + logger.error("An error occurred while attempting to filter metadata!", e); + } + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlResourceBackedMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlResourceBackedMetadataResolver.java index 67cde7971..0a4b2a7f2 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlResourceBackedMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlResourceBackedMetadataResolver.java @@ -5,7 +5,11 @@ import net.shibboleth.utilities.java.support.xml.ParserPool; import org.apache.lucene.index.IndexWriter; import org.joda.time.DateTime; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain; import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.IOException; @@ -13,7 +17,10 @@ /** * @author Bill Smith (wsmith@unicon.net) */ -public class OpenSamlResourceBackedMetadataResolver extends ResourceBackedMetadataResolver { +public class OpenSamlResourceBackedMetadataResolver extends ResourceBackedMetadataResolver implements Refilterable { + + private static final Logger logger = LoggerFactory.getLogger(OpenSamlResourceBackedMetadataResolver.class); + private IndexWriter indexWriter; private edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver sourceResolver; private OpenSamlMetadataResolverDelegate delegate; @@ -31,6 +38,9 @@ public OpenSamlResourceBackedMetadataResolver(ParserPool parserPool, OpenSamlMetadataResolverConstructorHelper.updateOpenSamlMetadataResolverFromReloadableMetadataResolverAttributes( this, sourceResolver.getReloadableMetadataResolverAttributes(), parserPool); + + //TODO: check if this is the right thing to do + this.setMetadataFilter(new MetadataFilterChain()); } // TODO: this is still probably not the best way to do this? @@ -48,4 +58,15 @@ protected void initMetadataResolver() throws ComponentInitializationException { this.sourceResolver.getResourceId(), indexWriter); } + + /** + * {@inheritDoc} + */ + public void refilter() { + try { + this.getBackingStore().setCachedFilteredMetadata(filterMetadata(getCachedOriginalMetadata())); + } catch (FilterException e) { + logger.error("An error occurred while attempting to filter metadata!", e); + } + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/Refilterable.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/Refilterable.java new file mode 100644 index 000000000..339a3b8e3 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/Refilterable.java @@ -0,0 +1,16 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml; + +/** + * Indicates that the resolver implementing this interface is a resolver that allows for its metadata to be + * filtered multiple times. + * + * @author Bill Smith (wsmith@unicon.net) + */ +public interface Refilterable { + + /** + * Reapply this resolver's filters to its cached, unfiltered metadata, and set the result back to its cached, + * filtered metadata. + */ + void refilter(); +} \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java index b1147fa3d..1ddcbb9a4 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java @@ -33,7 +33,6 @@ /** * @author Bill Smith (wsmith@unicon.net) */ -@Service public class MetadataResolverConverterServiceImpl implements MetadataResolverConverterService { @Autowired diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/OpenSamlChainingMetadataResolverUtil.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/OpenSamlChainingMetadataResolverUtil.java new file mode 100644 index 000000000..81b8f3675 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/OpenSamlChainingMetadataResolverUtil.java @@ -0,0 +1,20 @@ +package edu.internet2.tier.shibboleth.admin.util; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver; +import org.opensaml.saml.metadata.resolver.MetadataResolver; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +public class OpenSamlChainingMetadataResolverUtil { + + public static void updateChainingMetadataResolver(OpenSamlChainingMetadataResolver chainingMetadataResolver, MetadataResolver openSamlResolver) { + List resolverList = new ArrayList<>(chainingMetadataResolver.getResolvers()); + resolverList.removeIf(resolver -> resolver.getId().equals(openSamlResolver.getId())); + resolverList.add(openSamlResolver); + chainingMetadataResolver.setResolvers(resolverList); + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy index 06f9d0ca0..7f7beefe7 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerIntegrationTests.groovy @@ -3,12 +3,14 @@ package edu.internet2.tier.shibboleth.admin.ui.controller import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverConverterService import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility +import edu.internet2.tier.shibboleth.admin.util.OpenSamlChainingMetadataResolverUtil import groovy.json.JsonOutput import groovy.json.JsonSlurper -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -38,6 +40,12 @@ class MetadataFiltersControllerIntegrationTests extends Specification { @Autowired AttributeUtility attributeUtility + @Autowired + MetadataResolverConverterService metadataResolverConverterService + + @Autowired + MetadataResolver chainingMetadataResolver + ObjectMapper mapper TestObjectGenerator generator @@ -63,7 +71,8 @@ class MetadataFiltersControllerIntegrationTests extends Specification { def filterResourceId = resolver.metadataFilters[0].resourceId def resolverResourceId = resolver.resourceId metadataResolverRepository.save(resolver) - + MetadataResolver openSamlRepresentation = metadataResolverConverterService.convertToOpenSamlRepresentation(resolver) + OpenSamlChainingMetadataResolverUtil.updateChainingMetadataResolver((OpenSamlChainingMetadataResolver) chainingMetadataResolver, openSamlRepresentation) when: 'GET request is made with resource Id matching the existing filter' def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) @@ -86,7 +95,8 @@ class MetadataFiltersControllerIntegrationTests extends Specification { def filterResourceId = resolver.metadataFilters[0].resourceId def resolverResourceId = resolver.resourceId metadataResolverRepository.save(resolver) - + MetadataResolver openSamlRepresentation = metadataResolverConverterService.convertToOpenSamlRepresentation(resolver) + OpenSamlChainingMetadataResolverUtil.updateChainingMetadataResolver((OpenSamlChainingMetadataResolver) chainingMetadataResolver, openSamlRepresentation) when: 'GET request is made with resource Id matching the existing filter' def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId/Filters/$filterResourceId", String) @@ -182,7 +192,7 @@ class MetadataFiltersControllerIntegrationTests extends Specification { static class Config { @Bean MetadataResolver metadataResolver() { - new ChainingMetadataResolver().with { + new OpenSamlChainingMetadataResolver().with { it.id = 'tester' it.initialize() return it diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy index 221c5010e..69efa8133 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy @@ -7,12 +7,12 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFil 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.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import groovy.json.JsonOutput import groovy.json.JsonSlurper -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -315,7 +315,7 @@ class MetadataResolversControllerIntegrationTests extends Specification { static class Config { @Bean MetadataResolver metadataResolver() { - new ChainingMetadataResolver() + new OpenSamlChainingMetadataResolver() } } } 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 381ab3a18..316bfebbd 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 @@ -2,15 +2,16 @@ package edu.internet2.tier.shibboleth.admin.ui.service import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConverterConfiguration 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.domain.resolvers.opensaml.OpenSamlChainingMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository - import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import groovy.xml.DOMBuilder @@ -39,10 +40,9 @@ import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.util.TestHelpers.generatedXmlIsTheSameAsExpectedXml - @SpringBootTest @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, MetadataResolverConverterConfiguration, SearchConfiguration, InternationalizationConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @@ -65,6 +65,9 @@ class JPAMetadataResolverServiceImplTests extends Specification { @Autowired AttributeUtility attributeUtility + @Autowired + MetadataResolverConverterService mdrConverterService + TestObjectGenerator testObjectGenerator DOMBuilder domBuilder @@ -111,8 +114,13 @@ class JPAMetadataResolverServiceImplTests extends Specification { ''' when: - def mdr = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver().with { + def mdr = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver().with { + it.resourceId = "testme" it.name = "testme" + it.classpathMetadataResource = new ClasspathMetadataResource().with { + it.file = "metadata/aggregate.xml" + it + } it.metadataFilters.add(new EntityAttributesFilter().with { it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { it.entityAttributesFilterTargetType = EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY @@ -125,12 +133,14 @@ class JPAMetadataResolverServiceImplTests extends Specification { return it } metadataResolverRepository.save(mdr) + ((OpenSamlChainingMetadataResolver) metadataResolver).getResolvers().add(mdrConverterService.convertToOpenSamlRepresentation(mdr)) metadataResolverService.reloadFilters("testme") then: assert metadataResolverRepository.findAll().size() > 0 def ed = metadataResolver.resolveSingle(new CriteriaSet(new EntityIdCriterion('http://test.scaldingspoon.org/test1'))) def resultString = openSamlObjects.marshalToXmlString(ed) + println(resultString) def diff = DiffBuilder.compare(Input.fromString(expectedXML)).withTest(Input.fromString(resultString)).ignoreComments().ignoreWhitespace().build() !diff.hasDifferences() } @@ -302,9 +312,10 @@ class JPAMetadataResolverServiceImplTests extends Specification { it } - return new ChainingMetadataResolver().with { + return new OpenSamlChainingMetadataResolver().with { it.id = 'chain' - it.resolvers = [aggregate] + //it.resolvers = [aggregate] +// it.resolvers = [] it.initialize() it } 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 3faa17cdf..0c7fe9abf 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 @@ -2,6 +2,7 @@ package edu.internet2.tier.shibboleth.admin.ui.util import edu.internet2.tier.shibboleth.admin.ui.domain.* import edu.internet2.tier.shibboleth.admin.ui.domain.filters.* +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget.EntityAttributesFilterTargetType import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterTargetRepresentation import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.RelyingPartyOverridesRepresentation @@ -321,11 +322,23 @@ class TestObjectGenerator { return representation } + String buildEntityAttributesFilterTargetValueByType(EntityAttributesFilterTargetType type) { + switch (type) { + case EntityAttributesFilterTargetType.ENTITY: + return generator.randomString() + case EntityAttributesFilterTargetType.CONDITION_SCRIPT: + return "eval(true);" + case EntityAttributesFilterTargetType.REGEX: + return "/foo.*/" + } + } + EntityAttributesFilterTarget buildEntityAttributesFilterTarget() { EntityAttributesFilterTarget entityAttributesFilterTarget = new EntityAttributesFilterTarget() - entityAttributesFilterTarget.setSingleValue(generator.randomString()) entityAttributesFilterTarget.setEntityAttributesFilterTargetType(randomFilterTargetType()) + entityAttributesFilterTarget.setSingleValue( + buildEntityAttributesFilterTargetValueByType(entityAttributesFilterTarget.getEntityAttributesFilterTargetType())) return entityAttributesFilterTarget } @@ -353,8 +366,10 @@ class TestObjectGenerator { FilterTargetRepresentation buildFilterTargetRepresentation() { FilterTargetRepresentation representation = new FilterTargetRepresentation() - representation.setValue(generator.randomStringList()) representation.setType(randomFilterTargetType().toString()) + representation.setValue([ + buildEntityAttributesFilterTargetValueByType(EntityAttributesFilterTargetType.valueOf(representation.getType())) + ]) return representation } @@ -460,9 +475,6 @@ class TestObjectGenerator { it.metadataURL = 'https://idp.unicon.net/idp/shibboleth' it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes().with { - it.minRefreshDelay = 'PT5M' - it.maxRefreshDelay = 'PT1H' - it.refreshDelayFactor = 0.75 it } it diff --git a/backend/src/test/resources/conf/278.2.xml b/backend/src/test/resources/conf/278.2.xml index a7adef87f..ad3cb6c44 100644 --- a/backend/src/test/resources/conf/278.2.xml +++ b/backend/src/test/resources/conf/278.2.xml @@ -39,10 +39,8 @@ + metadataURL="https://idp.unicon.net/idp/shibboleth"> + diff --git a/backend/src/test/resources/conf/278.xml b/backend/src/test/resources/conf/278.xml index e44ce7ee3..cb5317531 100644 --- a/backend/src/test/resources/conf/278.xml +++ b/backend/src/test/resources/conf/278.xml @@ -32,10 +32,7 @@ + metadataURL="https://idp.unicon.net/idp/shibboleth"> diff --git a/backend/src/test/resources/conf/532.xml b/backend/src/test/resources/conf/532.xml index 51b5276ee..b2be43498 100644 --- a/backend/src/test/resources/conf/532.xml +++ b/backend/src/test/resources/conf/532.xml @@ -8,8 +8,6 @@ + metadataURL="https://idp.unicon.net/idp/shibboleth" /> +