From 22cb57c17c7b6d8ce6d69110dfb2aa268a1a9c26 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 30 Sep 2019 10:16:59 -0400 Subject: [PATCH 1/4] SHIBUI-1501 --- ...lerVersionEndpointsIntegrationTests.groovy | 67 +++++++++++++++++++ ...MetadataFilterEnversVersioningTests.groovy | 43 ++++++++++++ .../MetadataResolversController.java | 1 + .../ui/domain/resolvers/MetadataResolver.java | 11 +++ .../EnversMetadataResolverVersionService.java | 13 +++- .../util/AttributeReleaseAndOverridesX.groovy | 13 ++++ 6 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy index 8e23362e7..0e10dbac9 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy @@ -1,5 +1,9 @@ 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.configuration.CustomPropertiesConfiguration 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.EntityRoleWhiteListFilter @@ -11,10 +15,15 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FilesystemMetadat import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverVersionService +import edu.internet2.tier.shibboleth.admin.ui.util.AttributeReleaseAndOverridesX +import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator +import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.test.context.ActiveProfiles +import org.springframework.transaction.PlatformTransactionManager import spock.lang.Specification import static edu.internet2.tier.shibboleth.admin.ui.domain.filters.NameIdFormatFilterTarget.NameIdFormatFilterTargetType.ENTITY @@ -32,12 +41,34 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi @Autowired MetadataResolverRepository repository + @Autowired + AttributeUtility attributeUtility + + @Autowired + CustomPropertiesConfiguration customPropertiesConfiguration + + ObjectMapper mapper + TestObjectGenerator generator + + @Autowired + PlatformTransactionManager txMgr + + @Autowired + MetadataResolverVersionService metadataResolverVersionService + static BASE_URI = '/api/MetadataResolvers' static ALL_VERSIONS_URI = "$BASE_URI/%s/Versions" static SPECIFIC_VERSION_URI = "$BASE_URI/%s/Versions/%s" + def setup() { + generator = new TestObjectGenerator(attributeUtility, customPropertiesConfiguration) + mapper = new ObjectMapper() + mapper.enable(SerializationFeature.INDENT_OUTPUT) + mapper.registerModule(new JavaTimeModule()) + } + def "GET /api/MetadataResolvers/{resourceId}/Versions with non-existent resolver"() { when: def result = getAllMetadataResolverVersions('non-existent-resolver-id', String) @@ -111,6 +142,7 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi } def "SHIBUI-1386"() { + given: MetadataResolver mr = new FileBackedHttpMetadataResolver(name: 'testme') mr = repository.save(mr) @@ -142,6 +174,7 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi } def "SHIBUI-1500"() { + given: MetadataResolver mr = new FileBackedHttpMetadataResolver(name: 'shibui-1500') mr = repository.save(mr) @@ -159,6 +192,7 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi } def "SHIBUI-1499"() { + given: MetadataResolver mr = new FileBackedHttpMetadataResolver(name: 'shibui-1499') mr = repository.save(mr) @@ -182,6 +216,29 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi noExceptionThrown() } + def "SHIBUI-1501"() { + given: + def mr = new FileBackedHttpMetadataResolver(name: 'shibui-1501') + mr = repository.save(mr) + + when: 'add a filter' + EntityAttributesFilter filter = this.generator.entityAttributesFilter() + mr.addFilter(filter) + def resolver = (repository.save(mr) as MetadataResolver).withTraits AttributeReleaseAndOverrides + resolver.entityAttributesFilterIntoTransientRepresentation() + + def allVersions = getAllMetadataResolverVersions(mr.resourceId, List) + def mrv2 = getMetadataResolverForVersion(mr.resourceId, allVersions.body[1].id, MetadataResolver) + .body.withTraits AttributeReleaseAndOverrides + + then: + mrv2.metadataFilters.size() == 1 + mrv2.attributesRelease(0).size() == resolver.attributesRelease(0).size() + mrv2.overrides(0).size() == resolver.overrides(0).size() + mrv2.attributesRelease(0) == resolver.attributesRelease(0) + mrv2.overrides(0) == resolver.overrides(0) + } + private getAllMetadataResolverVersions(String resourceId, responseType) { this.restTemplate.getForEntity(resourceUriFor(ALL_VERSIONS_URI, resourceId), responseType) } @@ -198,3 +255,13 @@ class MetadataResolverControllerVersionEndpointsIntegrationTests extends Specifi String.format(uriTemplate, resourceId) } } + +trait AttributeReleaseAndOverrides { + List attributesRelease(int filterIndex) { + (this.metadataFilters[filterIndex] as EntityAttributesFilter).attributeRelease + } + + Map overrides(int filterIndex) { + (this.metadataFilters[filterIndex] as EntityAttributesFilter).relyingPartyOverrides + } +} diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy index fe1e5eee4..366dc9c0d 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy @@ -1,6 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.repository.envers +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.configuration.CoreShibUiConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.EntitiesVersioningConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration @@ -19,6 +23,8 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMet import edu.internet2.tier.shibboleth.admin.ui.repository.FilterRepository import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverVersionService +import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator +import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest @@ -49,6 +55,22 @@ class MetadataFilterEnversVersioningTests extends Specification { @Autowired PlatformTransactionManager txMgr + @Autowired + AttributeUtility attributeUtility + + @Autowired + CustomPropertiesConfiguration customPropertiesConfiguration + + ObjectMapper mapper + TestObjectGenerator generator + + def setup() { + generator = new TestObjectGenerator(attributeUtility, customPropertiesConfiguration) + mapper = new ObjectMapper() + mapper.enable(SerializationFeature.INDENT_OUTPUT) + mapper.registerModule(new JavaTimeModule()) + } + def "test versioning of MetadataResolver with EntityRoleWhiteListFilter"() { when: 'Add initial filter' @@ -312,4 +334,25 @@ class MetadataFilterEnversVersioningTests extends Specification { mrv1.metadataFilters.size() == 1 mrv2.metadataFilters.size() == 0 } + + def "SHIBUI-1501"() { + when: 'Add initial filter' + def mr = new FileBackedHttpMetadataResolver(name: 'resolver') + mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { + metadataResolverRepository.save(mr) + } + EntityAttributesFilter filter = this.generator.entityAttributesFilter() + mr.metadataFilters.add(filter) + mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { + metadataResolverRepository.save(mr) + } + def versions = metadataResolverVersionService.findVersionsForMetadataResolver(mr.resourceId) + def mrv1 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, versions[0].id) + def mrv2 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, versions[1].id) + + then: + versions.size() == 2 + mrv1.metadataFilters.size() == 0 + mrv2.metadataFilters.size() == 1 + } } 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 dbdc0ddd1..e07272629 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 @@ -170,6 +170,7 @@ public ResponseEntity getAllVersions(@PathVariable String resourceId) { } @GetMapping("/MetadataResolvers/{resourceId}/Versions/{versionId}") + @Transactional(readOnly = true) public ResponseEntity getSpecificVersion(@PathVariable String resourceId, @PathVariable String versionId) { MetadataResolver resolver = versionService.findSpecificVersionOfMetadataResolver(resourceId, versionId); if (resolver == null) { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java index 9e67a5549..d24cd3638 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -100,4 +101,14 @@ public void addFilter(MetadataFilter metadataFilter) { public void markAsModified() { this.versionModifiedTimestamp = System.currentTimeMillis(); } + + public void entityAttributesFilterIntoTransientRepresentation() { + //expose explicit API to call to convert into transient representation + //used in unit/integration tests where JPA's @PostLoad callback execution engine is not available + this.metadataFilters + .stream() + .filter(EntityAttributesFilter.class::isInstance) + .map(EntityAttributesFilter.class::cast) + .forEach(EntityAttributesFilter::intoTransientRepresentation); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EnversMetadataResolverVersionService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EnversMetadataResolverVersionService.java index c98203eca..b0d90195f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EnversMetadataResolverVersionService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EnversMetadataResolverVersionService.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.domain.versioning.Version; import edu.internet2.tier.shibboleth.admin.ui.envers.EnversVersionServiceSupport; @@ -27,6 +28,16 @@ public List findVersionsForMetadataResolver(String resourceId) { @Override public MetadataResolver findSpecificVersionOfMetadataResolver(String resourceId, String versionId) { Object mrObject = enversVersionServiceSupport.findSpecificVersionOfPersistentEntity(resourceId, versionId, MetadataResolver.class); - return mrObject == null ? null : (MetadataResolver) mrObject; + if(mrObject == null) { + return null; + } + MetadataResolver resolver = (MetadataResolver) mrObject; + + //The @PostLoad is not honored by Envers. So need to do this manually for EntityAttributesFilters + //So the correct representation is built and returned to upstream clients expecting JSON + resolver.entityAttributesFilterIntoTransientRepresentation(); + + return resolver; + } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy new file mode 100644 index 000000000..d3198d225 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy @@ -0,0 +1,13 @@ +package edu.internet2.tier.shibboleth.admin.ui.util + +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter + +trait AttributeReleaseAndOverridesX { + List attributesRelease(int filterIndex) { + (this.metadataFilters[filterIndex] as EntityAttributesFilter).attributeRelease + } + + Map overrides() { + (this.metadataFilters[filterIndex] as EntityAttributesFilter).relyingPartyOverrides + } +} From f4ce06f2fb3dad4a15101bf626df7a6d13a80eba Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 30 Sep 2019 10:18:04 -0400 Subject: [PATCH 2/4] SHIBUI-1501: cleanup --- .../ui/util/AttributeReleaseAndOverridesX.groovy | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy deleted file mode 100644 index d3198d225..000000000 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/AttributeReleaseAndOverridesX.groovy +++ /dev/null @@ -1,13 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.util - -import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter - -trait AttributeReleaseAndOverridesX { - List attributesRelease(int filterIndex) { - (this.metadataFilters[filterIndex] as EntityAttributesFilter).attributeRelease - } - - Map overrides() { - (this.metadataFilters[filterIndex] as EntityAttributesFilter).relyingPartyOverrides - } -} From 21ef140bf25b4654308a579d158f7bb77e14b2c7 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 30 Sep 2019 10:24:52 -0400 Subject: [PATCH 3/4] SHIBUI-1501: cleanup --- ...dataResolverControllerVersionEndpointsIntegrationTests.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy index 0e10dbac9..d1bf151d3 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolverControllerVersionEndpointsIntegrationTests.groovy @@ -16,7 +16,6 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.LocalDynamicMetad import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverVersionService -import edu.internet2.tier.shibboleth.admin.ui.util.AttributeReleaseAndOverridesX import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility import org.springframework.beans.factory.annotation.Autowired From 25bc0af217bbb8a2cc4d8b855f054d2c7f17a896 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 30 Sep 2019 11:21:33 -0400 Subject: [PATCH 4/4] Fix tests --- ...MetadataFilterEnversVersioningTests.groovy | 21 ------------------- .../filters/EntityAttributesFilter.java | 3 +++ 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy index 366dc9c0d..6df7da461 100644 --- a/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy +++ b/backend/src/enversTest/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/envers/MetadataFilterEnversVersioningTests.groovy @@ -334,25 +334,4 @@ class MetadataFilterEnversVersioningTests extends Specification { mrv1.metadataFilters.size() == 1 mrv2.metadataFilters.size() == 0 } - - def "SHIBUI-1501"() { - when: 'Add initial filter' - def mr = new FileBackedHttpMetadataResolver(name: 'resolver') - mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { - metadataResolverRepository.save(mr) - } - EntityAttributesFilter filter = this.generator.entityAttributesFilter() - mr.metadataFilters.add(filter) - mr = EnversTestsSupport.doInExplicitTransaction(txMgr) { - metadataResolverRepository.save(mr) - } - def versions = metadataResolverVersionService.findVersionsForMetadataResolver(mr.resourceId) - def mrv1 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, versions[0].id) - def mrv2 = metadataResolverVersionService.findSpecificVersionOfMetadataResolver(mr.resourceId, versions[1].id) - - then: - versions.size() == 2 - mrv1.metadataFilters.size() == 0 - mrv2.metadataFilters.size() == 1 - } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java index 5d6d3132a..a3e0a6a93 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilter.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getAttributeListFromAttributeReleaseList; import static edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions.getAttributeListFromRelyingPartyOverridesRepresentation; @@ -69,6 +70,8 @@ private void rebuildAttributes() { @PostLoad public void intoTransientRepresentation() { + //For some update operations, list of attributes could contain null values. Filter them out + this.attributes.removeIf(Objects::isNull); this.attributeRelease = getAttributeReleaseListFromAttributeList(this.attributes); this.relyingPartyOverrides = getRelyingPartyOverridesRepresentationFromAttributeList(this.attributes); }