From c9e81161070d94190dfd88c2591b53df700f2388 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 21 Jun 2018 10:55:05 -0400 Subject: [PATCH 01/17] SHIBUI-521(545): Refactoring to polymorphic JSON serialization of metadata resolvers Work in progress... --- .../DynamicHttpMetadataResolver.java | 3 + .../FileBackedHttpMetadataResolver.java | 5 +- .../LocalDynamicMetadataResolver.java | 6 +- .../ui/domain/resolvers/MetadataResolver.java | 17 +- ...orphicResolversJacksonHandlingTests.groovy | 363 ++++++++++++++++++ 5 files changed, 388 insertions(+), 6 deletions(-) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy 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 0910c9050..e1c9ddc6b 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 @@ -21,6 +21,8 @@ @ToString public class DynamicHttpMetadataResolver extends MetadataResolver { + + public static final String DEFAULT_TIMEOUT = "PT5S"; @Embedded @@ -38,6 +40,7 @@ public class DynamicHttpMetadataResolver extends MetadataResolver { private List supportedContentTypes; public DynamicHttpMetadataResolver() { + type = "DynamicHttpMetadataResolver"; this.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes(); this.httpMetadataResolverAttributes.setConnectionRequestTimeout(DEFAULT_TIMEOUT); this.httpMetadataResolverAttributes.setConnectionTimeout(DEFAULT_TIMEOUT); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java index 37748e6c0..f659a412b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java @@ -11,12 +11,15 @@ @Entity @EqualsAndHashCode(callSuper = true) -@NoArgsConstructor @Getter @Setter @ToString public class FileBackedHttpMetadataResolver extends MetadataResolver { + public FileBackedHttpMetadataResolver() { + type = "FileBackedHttpMetadataResolver"; + } + private String metadataURL; private String backingFile; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/LocalDynamicMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/LocalDynamicMetadataResolver.java index 63ec78eb5..2bdb67d1f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/LocalDynamicMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/LocalDynamicMetadataResolver.java @@ -2,7 +2,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; @@ -11,12 +10,15 @@ @Entity @EqualsAndHashCode(callSuper = true) -@NoArgsConstructor @Getter @Setter @ToString public class LocalDynamicMetadataResolver extends MetadataResolver { + public LocalDynamicMetadataResolver() { + type = "LocalDynamicMetadataResolver"; + } + private String sourceDirectory; private String sourceManagerRef; 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 1bbafefba..44d8c6e97 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 @@ -1,5 +1,8 @@ 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 edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter; import lombok.EqualsAndHashCode; @@ -22,17 +25,25 @@ @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -@EqualsAndHashCode(callSuper = true, exclude={"version"}) +@EqualsAndHashCode(callSuper = true, exclude = {"version"}) @NoArgsConstructor @Getter @Setter @ToString +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "@type", visible = true) +@JsonSubTypes({@JsonSubTypes.Type(value = LocalDynamicMetadataResolver.class, name = "LocalDynamicMetadataResolver"), + @JsonSubTypes.Type(value = FileBackedHttpMetadataResolver.class, name = "FileBackedHttpMetadataResolver"), + @JsonSubTypes.Type(value = DynamicHttpMetadataResolver.class, name = "DynamicHttpMetadataResolver")}) public class MetadataResolver extends AbstractAuditable { - @Column(unique=true) + @JsonProperty("@type") + @Transient + String type; + + @Column(unique = true) private String name; - @Column(unique=true) + @Column(unique = true) private String resourceId = UUID.randomUUID().toString(); private Boolean requireValidMetadata = true; diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy new file mode 100644 index 000000000..2ed5eda32 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy @@ -0,0 +1,363 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityRoleWhiteListFilter +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.HttpMetadataResolverAttributes +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.domain.resolvers.ReloadableMetadataResolverAttributes +import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator +import edu.internet2.tier.shibboleth.admin.util.AttributeUtility +import spock.lang.Specification + +class PolymorphicResolversJacksonHandlingTests extends Specification { + + ObjectMapper mapper + + AttributeUtility attributeUtility + + TestObjectGenerator testObjectGenerator + + def setup() { + mapper = new ObjectMapper() + mapper.enable(SerializationFeature.INDENT_OUTPUT) + + attributeUtility = new AttributeUtility(new OpenSamlObjects().with { + it.init() + it + }) + testObjectGenerator = new TestObjectGenerator(attributeUtility) + } + + def "Correct polymorphic serialization of LocalDynamicMetadataResolver"() { + given: + def givenResolverJson = """ + { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : null, + "requireValidMetadata" : true, + "failFastInitialization" : true, + "sortKey" : null, + "criterionPredicateRegistryRef" : null, + "useDefaultPredicateRegistry" : true, + "satisfyAnyPredicates" : false, + "metadataFilters" : [ { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityAttributes", + "filterEnabled" : false, + "version" : 463855403, + "entityAttributesFilterTarget" : { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "entityAttributesFilterTargetType" : "ENTITY", + "value" : [ "CedewbJJET" ], + "audId" : null + }, + "attributeRelease" : [ "9ktPyjjiCn" ], + "relyingPartyOverrides" : { + "signAssertion" : false, + "dontSignResponse" : true, + "turnOffEncryption" : true, + "useSha" : false, + "ignoreAuthenticationMethod" : false, + "omitNotBefore" : true, + "responderId" : null, + "nameIdFormats" : [ ], + "authenticationMethods" : [ ] + }, + "audId" : null, + "@type" : "EntityAttributes" + }, { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityRoleWhiteList", + "filterEnabled" : false, + "version" : 0, + "removeRolelessEntityDescriptors" : true, + "removeEmptyEntitiesDescriptors" : true, + "retainedRoles" : [ "role1", "role2" ], + "audId" : null, + "@type" : "EntityRoleWhiteList" + } ], + "version" : 0, + "sourceDirectory" : "dir", + "sourceManagerRef" : null, + "sourceKeyGeneratorRef" : null, + "audId" : null, + "@type" : "LocalDynamicMetadataResolver" + } + """ + + when: + def deSerializedResolver = mapper.readValue(givenResolverJson, MetadataResolver) + def json = mapper.writeValueAsString(deSerializedResolver) + println(json) + def roundTripResolver = mapper.readValue(json, MetadataResolver) + + + then: + roundTripResolver == deSerializedResolver + deSerializedResolver instanceof LocalDynamicMetadataResolver + deSerializedResolver.metadataFilters.size() == 2 + deSerializedResolver.metadataFilters[0] instanceof EntityAttributesFilter + deSerializedResolver.metadataFilters[1] instanceof EntityRoleWhiteListFilter + } + + def "Correct polymorphic serialization of DynamicHttpMetadataResolver"() { + given: + def givenResolverJson = """ + { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : null, + "resourceId" : "248168e2-7ccb-424e-8480-263f3df32034", + "requireValidMetadata" : true, + "failFastInitialization" : true, + "sortKey" : null, + "criterionPredicateRegistryRef" : null, + "useDefaultPredicateRegistry" : true, + "satisfyAnyPredicates" : false, + "metadataFilters" : [ { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityAttributes", + "resourceId" : "3bc95d7d-4db6-4f56-a99b-8da2163a936c", + "filterEnabled" : false, + "version" : -107872130, + "entityAttributesFilterTarget" : { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "entityAttributesFilterTargetType" : "ENTITY", + "value" : [ "ohD3PFTEoJ" ], + "audId" : null + }, + "attributeRelease" : [ "CsYlANiTHt" ], + "relyingPartyOverrides" : { + "signAssertion" : true, + "dontSignResponse" : false, + "turnOffEncryption" : true, + "useSha" : true, + "ignoreAuthenticationMethod" : true, + "omitNotBefore" : true, + "responderId" : "310c2919-ee78-4c61-8f03-b653212cfdfb", + "nameIdFormats" : [ "cYAVB5imC2" ], + "authenticationMethods" : [ ] + }, + "audId" : null, + "@type" : "EntityAttributes" + }, { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityRoleWhiteList", + "resourceId" : "e68c84c5-c1d9-45c9-bddc-336b55ebe3ed", + "filterEnabled" : false, + "version" : 0, + "removeRolelessEntityDescriptors" : true, + "removeEmptyEntitiesDescriptors" : true, + "retainedRoles" : [ "role1", "role2" ], + "audId" : null, + "@type" : "EntityRoleWhiteList" + } ], + "version" : 0, + "dynamicMetadataResolverAttributes" : { + "parserPoolRef" : null, + "taskTimerRef" : null, + "refreshDelayFactor" : 0.75, + "minCacheDuration" : "PT10M", + "maxCacheDuration" : "PT8H", + "maxIdleEntityData" : "PT8H", + "removeIdleEntityData" : null, + "cleanupTaskInterval" : "PT30M", + "persistentCacheManagerRef" : null, + "persistentCacheManagerDirectory" : null, + "persistentCacheKeyGeneratorRef" : null, + "initializeFromPersistentCacheInBackground" : true, + "backgroundInitializationFromCacheDelay" : "PT2S", + "initializationFromCachePredicateRef" : null + }, + "httpMetadataResolverAttributes" : { + "httpClientRef" : null, + "connectionRequestTimeout" : null, + "connectionTimeout" : null, + "socketTimeout" : null, + "disregardTLSCertificate" : false, + "tlsTrustEngineRef" : null, + "httpClientSecurityParametersRef" : null, + "proxyHost" : null, + "proxyPort" : null, + "proxyUser" : null, + "proxyPassword" : null, + "httpCaching" : null, + "httpCacheDirectory" : null, + "httpMaxCacheEntries" : null, + "httpMaxCacheEntrySize" : null + }, + "maxConnectionsTotal" : 100, + "maxConnectionsPerRoute" : 100, + "supportedContentTypes" : null, + "audId" : null, + "@type" : "DynamicHttpMetadataResolver" + } + """ + + when: + def deSerializedResolver = mapper.readValue(givenResolverJson, MetadataResolver) + def json = mapper.writeValueAsString(deSerializedResolver) + println(json) + def roundTripResolver = mapper.readValue(json, MetadataResolver) + + + then: + roundTripResolver == deSerializedResolver + deSerializedResolver instanceof DynamicHttpMetadataResolver + deSerializedResolver.metadataFilters.size() == 2 + deSerializedResolver.metadataFilters[0] instanceof EntityAttributesFilter + deSerializedResolver.metadataFilters[1] instanceof EntityRoleWhiteListFilter + } + + def "Correct polymorphic serialization of FileBackedHttpMetadataResolver"() { + given: + MetadataResolver resolver = new FileBackedHttpMetadataResolver().with { + it.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes() + it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes() + it.metadataFilters = [testObjectGenerator.entityAttributesFilter(), testObjectGenerator.entityRoleWhitelistFilter()] + it + } + def givenResolverJson = """ + { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : null, + "resourceId" : "f3e615d5-960b-4fed-bff6-86fc4620be95", + "requireValidMetadata" : true, + "failFastInitialization" : true, + "sortKey" : null, + "criterionPredicateRegistryRef" : null, + "useDefaultPredicateRegistry" : true, + "satisfyAnyPredicates" : false, + "metadataFilters" : [ { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityAttributes", + "resourceId" : "4149cc5f-137e-4045-9369-8fedafcdd8c8", + "filterEnabled" : false, + "version" : -1249726767, + "entityAttributesFilterTarget" : { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "entityAttributesFilterTargetType" : "CONDITION_SCRIPT", + "value" : [ "6EksoLF7Q0" ], + "audId" : null + }, + "attributeRelease" : [ ], + "relyingPartyOverrides" : { + "signAssertion" : false, + "dontSignResponse" : true, + "turnOffEncryption" : false, + "useSha" : false, + "ignoreAuthenticationMethod" : false, + "omitNotBefore" : false, + "responderId" : "3267361e-7d8c-45d2-92ce-7642dc3bb432", + "nameIdFormats" : [ "baHO7CzFHH" ], + "authenticationMethods" : [ ] + }, + "audId" : null, + "@type" : "EntityAttributes" + }, { + "createdDate" : null, + "modifiedDate" : null, + "createdBy" : null, + "modifiedBy" : null, + "name" : "EntityRoleWhiteList", + "resourceId" : "75117ec7-c74a-45cb-b216-cbbc9118fe70", + "filterEnabled" : false, + "version" : 0, + "removeRolelessEntityDescriptors" : true, + "removeEmptyEntitiesDescriptors" : true, + "retainedRoles" : [ "role1", "role2" ], + "audId" : null, + "@type" : "EntityRoleWhiteList" + } ], + "version" : 0, + "metadataURL" : null, + "backingFile" : null, + "initializeFromBackupFile" : true, + "backupFileInitNextRefreshDelay" : null, + "reloadableMetadataResolverAttributes" : { + "parserPoolRef" : null, + "taskTimerRef" : null, + "minRefreshDelay" : null, + "maxRefreshDelay" : null, + "refreshDelayFactor" : null, + "indexesRef" : null, + "resolveViaPredicatesOnly" : null, + "expirationWarningThreshold" : null + }, + "httpMetadataResolverAttributes" : { + "httpClientRef" : null, + "connectionRequestTimeout" : null, + "connectionTimeout" : null, + "socketTimeout" : null, + "disregardTLSCertificate" : false, + "tlsTrustEngineRef" : null, + "httpClientSecurityParametersRef" : null, + "proxyHost" : null, + "proxyPort" : null, + "proxyUser" : null, + "proxyPassword" : null, + "httpCaching" : null, + "httpCacheDirectory" : null, + "httpMaxCacheEntries" : null, + "httpMaxCacheEntrySize" : null + }, + "audId" : null, + "@type" : "FileBackedHttpMetadataResolver" + } + """ + + when: + //println mapper.writeValueAsString(resolver) + def deSerializedResolver = mapper.readValue(givenResolverJson, MetadataResolver) + def json = mapper.writeValueAsString(deSerializedResolver) + println(json) + def roundTripResolver = mapper.readValue(json, MetadataResolver) + + + then: + true + roundTripResolver == deSerializedResolver + deSerializedResolver instanceof FileBackedHttpMetadataResolver + deSerializedResolver.metadataFilters.size() == 2 + deSerializedResolver.metadataFilters[0] instanceof EntityAttributesFilter + deSerializedResolver.metadataFilters[1] instanceof EntityRoleWhiteListFilter + } +} From 56aa5b43a5d8d6c238c6ad3e2e36c5c3dfc69bd9 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 21 Jun 2018 14:34:26 -0400 Subject: [PATCH 02/17] SHIBUI-521(545): tests --- ...=> MetadataResolverRepositoryTests.groovy} | 98 ++++++++++++------- 1 file changed, 65 insertions(+), 33 deletions(-) rename backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/{MetadataResolverRepositoryTest.groovy => MetadataResolverRepositoryTests.groovy} (75%) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy similarity index 75% rename from backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTest.groovy rename to backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index cf87e218c..97e15c827 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -6,6 +6,9 @@ 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.frontend.RelyingPartyOverridesRepresentation +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.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.service.JPAEntityDescriptorServiceImpl @@ -24,11 +27,11 @@ import javax.persistence.EntityManager * A highly unnecessary test so that I can check to make sure that persistence is correct for the model */ @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) +@ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) -class MetadataResolverRepositoryTest extends Specification { +class MetadataResolverRepositoryTests extends Specification { @Autowired MetadataResolverRepository metadataResolverRepository @@ -42,44 +45,16 @@ class MetadataResolverRepositoryTest extends Specification { def "test persisting a metadata resolver"() { when: - def mdr = new MetadataResolver().with { - it.name = "testme" - it.metadataFilters.add(new EntityAttributesFilter().with { - it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { - it.entityAttributesFilterTargetType = EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY - it.value = ["hola"] - return it - } - return it - }) - return it - } + def mdr = create { new MetadataResolver() } metadataResolverRepository.save(mdr) then: - metadataResolverRepository.findAll().size() > 0 - MetadataResolver item = metadataResolverRepository.findByName("testme") - item.name == "testme" - item.metadataFilters.size() == 1 - item.metadataFilters.get(0).entityAttributesFilterTarget.entityAttributesFilterTargetType == EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY - item.metadataFilters.get(0).entityAttributesFilterTarget.value.size() == 1 - item.metadataFilters.get(0).entityAttributesFilterTarget.value.get(0) == "hola" + basicPersistenceOfResolverIsCorrectFor { it instanceof DynamicHttpMetadataResolver } } def "SHIBUI-553"() { when: - def mdr = new MetadataResolver().with { - it.name = "testme" - it.metadataFilters.add(new EntityAttributesFilter().with { - it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { - it.entityAttributesFilterTargetType = EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY - it.setSingleValue(["hola"]) - return it - } - return it - }) - return it - } + def mdr = create { new MetadataResolver() } metadataResolverRepository.save(mdr) def item1 = metadataResolverRepository.findByName('testme') @@ -200,4 +175,61 @@ class MetadataResolverRepositoryTest extends Specification { !persistedFilter.relyingPartyOverrides.signAssertion } + def "test persisting DynamicHttpMetadataResolver "() { + when: + def mdr = create { new DynamicHttpMetadataResolver() } + metadataResolverRepository.save(mdr) + + then: + basicPersistenceOfResolverIsCorrectFor { it instanceof DynamicHttpMetadataResolver } + } + + def "test persisting FileBackedHttpMetadataResolver "() { + when: + def mdr = create { new FileBackedHttpMetadataResolver() } + metadataResolverRepository.save(mdr) + + then: + basicPersistenceOfResolverIsCorrectFor { it instanceof FileBackedHttpMetadataResolver } + } + + def "test persisting LocalDynamicMetadataResolver "() { + when: + def mdr = create { new LocalDynamicMetadataResolver() } + metadataResolverRepository.save(mdr) + + then: + basicPersistenceOfResolverIsCorrectFor { it instanceof LocalDynamicMetadataResolver } + } + + + + private void basicPersistenceOfResolverIsCorrectFor(Closure resolverTypeCheck) { + assert metadataResolverRepository.findAll().size() > 0 + MetadataResolver item = metadataResolverRepository.findByName("testme") + assert resolverTypeCheck(item) + assert item.name == "testme" + assert item.metadataFilters.size() == 1 + assert item.metadataFilters.get(0).entityAttributesFilterTarget.entityAttributesFilterTargetType == EntityAttributesFilterTarget + .EntityAttributesFilterTargetType.ENTITY + assert item.metadataFilters.get(0).entityAttributesFilterTarget.value.size() == 1 + assert item.metadataFilters.get(0).entityAttributesFilterTarget.value.get(0) == "hola" + } + + private MetadataResolver create(Closure concreteResolverProvider) { + MetadataResolver resolver = concreteResolverProvider() + resolver.with { + it.name = "testme" + it.metadataFilters.add(new EntityAttributesFilter().with { + it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { + it.entityAttributesFilterTargetType = EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY + it.value = ["hola"] + return it + } + return it + }) + } + resolver + } + } From d864b36b2fa44995043e4ac4e1779a16b4f609c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 21 Jun 2018 15:03:56 -0400 Subject: [PATCH 03/17] SHIBUI-521(545): REST controller impl wip --- .../controller/MetadataFiltersController.java | 2 +- .../MetadataResolversController.java | 40 +++++++++++++++++++ .../MetadataResolverRepositoryTests.groovy | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java 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 9735b708f..65b53baac 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 @@ -30,7 +30,7 @@ import java.util.stream.Stream; @RestController -@RequestMapping("/api/MetadataResolver/{metadataResolverId}") +@RequestMapping("/api/MetadataResolvers/{metadataResolverId}") public class MetadataFiltersController { private static Logger LOGGER = LoggerFactory.getLogger(MetadataFiltersController.class); 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 new file mode 100644 index 000000000..d2890fb93 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversController.java @@ -0,0 +1,40 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api") +public class MetadataResolversController { + + @GetMapping("/MetadataResolvers") + ResponseEntity getAll() { + //TODO implement + return ResponseEntity.ok().build(); + } + + @GetMapping("/MetadataResolvers/{resourceId}") + ResponseEntity getOne(@PathVariable String resourceId) { + //TODO implement + return ResponseEntity.ok().build(); + } + + @PostMapping("/MetadataResolvers") + ResponseEntity create(@RequestBody MetadataResolver newResolver) { + //TODO implement + return ResponseEntity.ok().build(); + } + + @PutMapping("/MetadataResolvers/{resourceId}") + ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) { + //TODO implement + return ResponseEntity.ok().build(); + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index 97e15c827..2204d4d19 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -24,7 +24,7 @@ import spock.lang.Specification import javax.persistence.EntityManager /** - * A highly unnecessary test so that I can check to make sure that persistence is correct for the model + * Testing persistence of the MetadataResolver models */ @DataJpaTest @ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) From f0244db4d6a172acde31a905e159b5d15b3f4ea8 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 21 Jun 2018 17:09:13 -0400 Subject: [PATCH 04/17] SHIBUI-521(545): implementing controller --- .../MetadataResolversController.java | 65 ++++++++++++++++--- .../ui/domain/resolvers/MetadataResolver.java | 4 ++ 2 files changed, 61 insertions(+), 8 deletions(-) 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 d2890fb93..d6f0e6a26 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 @@ -1,7 +1,13 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import lombok.extern.log4j.Log4j; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -9,32 +15,75 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.net.URI; @RestController @RequestMapping("/api") +@Slf4j public class MetadataResolversController { + @Autowired + MetadataResolverRepository resolverRepository; + @GetMapping("/MetadataResolvers") + @Transactional(readOnly = true) ResponseEntity getAll() { - //TODO implement - return ResponseEntity.ok().build(); + Iterable resolvers = resolverRepository.findAll(); + resolvers.forEach(MetadataResolver::updateVersion); + return ResponseEntity.ok(resolvers); } @GetMapping("/MetadataResolvers/{resourceId}") + @Transactional(readOnly = true) ResponseEntity getOne(@PathVariable String resourceId) { - //TODO implement - return ResponseEntity.ok().build(); + MetadataResolver resolver = resolverRepository.findByResourceId(resourceId); + if (resolver == null) { + return ResponseEntity.notFound().build(); + } + resolver.updateVersion(); + return ResponseEntity.ok(resolver); } @PostMapping("/MetadataResolvers") + @Transactional ResponseEntity create(@RequestBody MetadataResolver newResolver) { - //TODO implement - return ResponseEntity.ok().build(); + //TODO disregard attached filters if any sent from UI? + //Only deal with filters via filters endpoints? + MetadataResolver persistedResolver = resolverRepository.save(newResolver); + persistedResolver.updateVersion(); + + return ResponseEntity.created(getResourceUriFor(persistedResolver)).body(persistedResolver); } @PutMapping("/MetadataResolvers/{resourceId}") + @Transactional ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) { - //TODO implement - return ResponseEntity.ok().build(); + //TODO disregard attached filters if any sent from UI? + //Only deal with filters via filters endpoints? And here only update the resolver pieces?? + MetadataResolver existingResolver = resolverRepository.findByResourceId(resourceId); + if (existingResolver == null) { + return ResponseEntity.notFound().build(); + } + if (existingResolver.hashCode() != updatedResolver.getVersion()) { + log.info("Metadata Resolver version conflict. Latest resolver in database version: {}. Resolver version sent from UI: {}", + existingResolver.hashCode(), updatedResolver.getVersion()); + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + + updatedResolver.setAudId(existingResolver.getAudId()); + MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); + persistedResolver.updateVersion(); + + return ResponseEntity.ok(persistedResolver); + } + + private static URI getResourceUriFor(MetadataResolver resolver) { + return ServletUriComponentsBuilder + .fromCurrentServletMapping().path("/api/MetadataResolvers/") + .pathSegment(resolver.getResourceId()) + .build() + .toUri(); } } 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 44d8c6e97..0062c9def 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 @@ -64,4 +64,8 @@ public class MetadataResolver extends AbstractAuditable { @Transient private int version; + + public void updateVersion() { + this.version = hashCode(); + } } From 1ab13b4fb127859adf07ea7ee78f978a3d78ffbd Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 21 Jun 2018 17:10:24 -0400 Subject: [PATCH 05/17] Polishing --- .../admin/ui/controller/MetadataResolversController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 d6f0e6a26..735082ba7 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 @@ -29,7 +29,7 @@ public class MetadataResolversController { @GetMapping("/MetadataResolvers") @Transactional(readOnly = true) - ResponseEntity getAll() { + public ResponseEntity getAll() { Iterable resolvers = resolverRepository.findAll(); resolvers.forEach(MetadataResolver::updateVersion); return ResponseEntity.ok(resolvers); @@ -37,7 +37,7 @@ ResponseEntity getAll() { @GetMapping("/MetadataResolvers/{resourceId}") @Transactional(readOnly = true) - ResponseEntity getOne(@PathVariable String resourceId) { + public ResponseEntity getOne(@PathVariable String resourceId) { MetadataResolver resolver = resolverRepository.findByResourceId(resourceId); if (resolver == null) { return ResponseEntity.notFound().build(); @@ -48,7 +48,7 @@ ResponseEntity getOne(@PathVariable String resourceId) { @PostMapping("/MetadataResolvers") @Transactional - ResponseEntity create(@RequestBody MetadataResolver newResolver) { + public ResponseEntity create(@RequestBody MetadataResolver newResolver) { //TODO disregard attached filters if any sent from UI? //Only deal with filters via filters endpoints? MetadataResolver persistedResolver = resolverRepository.save(newResolver); @@ -59,7 +59,7 @@ ResponseEntity create(@RequestBody MetadataResolver newResolver) { @PutMapping("/MetadataResolvers/{resourceId}") @Transactional - ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) { + public ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) { //TODO disregard attached filters if any sent from UI? //Only deal with filters via filters endpoints? And here only update the resolver pieces?? MetadataResolver existingResolver = resolverRepository.findByResourceId(resourceId); From a63107b96decd9fb218a765aa7da1a7dac54f7ed Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Fri, 22 Jun 2018 15:45:18 -0400 Subject: [PATCH 06/17] SHIBUI-521(545) controller integration tests wip --- .../ui/domain/resolvers/MetadataResolver.java | 2 +- ...ResolversControllerIntegrationTests.groovy | 81 +++++++++++++++++++ .../MetadataResolverRepositoryTests.groovy | 2 +- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy 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 0062c9def..4dae0762b 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 @@ -38,7 +38,7 @@ public class MetadataResolver extends AbstractAuditable { @JsonProperty("@type") @Transient - String type; + String type = "BaseMetadataResolver"; @Column(unique = true) private String name; 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 new file mode 100644 index 000000000..80c6fe52e --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataResolversControllerIntegrationTests.groovy @@ -0,0 +1,81 @@ +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.DynamicHttpMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import org.opensaml.saml.metadata.resolver.MetadataResolver +import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Bean +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.ActiveProfiles + +import spock.lang.Specification + +import javax.persistence.EntityManager + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("no-auth") +@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) +class MetadataResolversControllerIntegrationTests extends Specification { + + @Autowired + private TestRestTemplate restTemplate + + @Autowired + MetadataResolverRepository metadataResolverRepository + + @Autowired + EntityManager entityManager + + ObjectMapper mapper + + def setup() { + mapper = new ObjectMapper() + mapper.registerModule(new JavaTimeModule()) + mapper.enable(SerializationFeature.INDENT_OUTPUT) + } + + def "GET empty /api/MetadataResolvers"() { + when: + def result = this.restTemplate.getForEntity("/api/MetadataResolvers", String) + def returnedResolvers = mapper.readValue(result.body, + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver[]) + + then: + result.statusCodeValue == 200 + returnedResolvers.size() == 0 + } + + def "GET one DynamicHttpMetadataResolver /api/MetadataResolvers"() { + given: + def resolver = new DynamicHttpMetadataResolver().with { + it.name = 'Test DynamicHttpMetadataResolver' + it + } + metadataResolverRepository.save(resolver) + + when: + def result = this.restTemplate.getForEntity("/api/MetadataResolvers", String) + def returnedResolvers = mapper.readValue(result.body, + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver[]) + + then: + result.statusCodeValue == 200 + returnedResolvers.size() == 1 + returnedResolvers[0] instanceof DynamicHttpMetadataResolver + } + + @TestConfiguration + static class Config { + @Bean + MetadataResolver metadataResolver() { + new FilesystemMetadataResolver(new File('fake')) + } + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index 2204d4d19..0d4ffd64a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -49,7 +49,7 @@ class MetadataResolverRepositoryTests extends Specification { metadataResolverRepository.save(mdr) then: - basicPersistenceOfResolverIsCorrectFor { it instanceof DynamicHttpMetadataResolver } + basicPersistenceOfResolverIsCorrectFor { it instanceof MetadataResolver } } def "SHIBUI-553"() { From 0433995292e2480ae7f312fe6597570570fe8a60 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Fri, 22 Jun 2018 15:59:12 -0400 Subject: [PATCH 07/17] SHIBUI-521(544) tests --- .../MetadataResolversControllerIntegrationTests.groovy | 2 ++ 1 file changed, 2 insertions(+) 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 80c6fe52e..a60e5a1ad 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 @@ -69,6 +69,8 @@ class MetadataResolversControllerIntegrationTests extends Specification { result.statusCodeValue == 200 returnedResolvers.size() == 1 returnedResolvers[0] instanceof DynamicHttpMetadataResolver + returnedResolvers[0].name == 'Test DynamicHttpMetadataResolver' + } @TestConfiguration From 3e6dd33b4c128cdc350cdf5bdf01a65e4e767069 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 25 Jun 2018 08:52:30 -0400 Subject: [PATCH 08/17] SHIBUI-521(545): work in progress --- .../ui/controller/MetadataFiltersController.java | 2 +- .../ui/controller/MetadataResolversController.java | 4 +++- .../ui/domain/filters/EntityAttributesFilter.java | 2 +- .../admin/ui/domain/filters/MetadataFilter.java | 4 ++++ .../ui/domain/resolvers/MetadataResolver.java | 4 ++++ .../MetadataFiltersControllerTests.groovy | 14 +++++++------- 6 files changed, 20 insertions(+), 10 deletions(-) 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 65b53baac..75eea0984 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 @@ -179,7 +179,7 @@ else if(filterWithUpdatedData instanceof RequiredValidUntilFilter) { private static URI getResourceUriFor(MetadataResolver mr, String filterResourceId) { return ServletUriComponentsBuilder - .fromCurrentServletMapping().path("/api/MetadataResolver/") + .fromCurrentServletMapping().path("/api/MetadataResolvers/") .pathSegment(mr.getResourceId()) .pathSegment("Filters") .pathSegment(filterResourceId) 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 735082ba7..0078284e1 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 @@ -49,8 +49,10 @@ public ResponseEntity getOne(@PathVariable String resourceId) { @PostMapping("/MetadataResolvers") @Transactional public ResponseEntity create(@RequestBody MetadataResolver newResolver) { - //TODO disregard attached filters if any sent from UI? + //TODO: we are disregarding attached filters if any sent from UI below. //Only deal with filters via filters endpoints? + newResolver.clearAllFilters(); + MetadataResolver persistedResolver = resolverRepository.save(newResolver); persistedResolver.updateVersion(); 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 7b267d1ee..0208f92c4 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 @@ -55,7 +55,7 @@ public EntityAttributesFilter() { public void intoTransientRepresentation() { this.attributeRelease = getAttributeReleaseListFromAttributeList(this.attributes); this.relyingPartyOverrides = getRelyingPartyOverridesRepresentationFromAttributeList(attributes); - setVersion(hashCode()); + updateVersion(); } @PrePersist diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java index 3702bba3d..0473a4114 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/filters/MetadataFilter.java @@ -46,4 +46,8 @@ public class MetadataFilter extends AbstractAuditable { @Transient private int version; + + public void updateVersion() { + this.version = hashCode(); + } } 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 4dae0762b..adbb30f0d 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 @@ -68,4 +68,8 @@ public class MetadataResolver extends AbstractAuditable { public void updateVersion() { this.version = hashCode(); } + + public void clearAllFilters() { + this.metadataFilters.clear(); + } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy index 53cfb6a01..3cd5f00c0 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/MetadataFiltersControllerTests.groovy @@ -56,7 +56,7 @@ class MetadataFiltersControllerTests extends Specification { def mockMvc - def mockFilterService = Mock(FilterService) + static BASE_URI = '/api/MetadataResolvers' def setup() { randomGenerator = new RandomGenerator() @@ -93,7 +93,7 @@ class MetadataFiltersControllerTests extends Specification { def expectedResponseContentType = APPLICATION_JSON_UTF8 when: - def result = mockMvc.perform(get('/api/MetadataResolver/foo/Filters')) + def result = mockMvc.perform(get("$BASE_URI/foo/Filters")) println(mapper.writeValueAsString(expectedContent)) then: @@ -114,7 +114,7 @@ class MetadataFiltersControllerTests extends Specification { def expectedResponseContentType = APPLICATION_JSON_UTF8 when: - def result = mockMvc.perform(get("/api/MetadataResolver/foo/Filters/$expectedResourceId")) + def result = mockMvc.perform(get("$BASE_URI/foo/Filters/$expectedResourceId")) then: result.andExpect(expectedHttpResponseStatus) @@ -139,7 +139,7 @@ class MetadataFiltersControllerTests extends Specification { def expectedMetadataResolverUUID = metadataResolver.getResourceId() def expectedFilterUUID = randomFilter.getResourceId() def expectedResponseHeader = 'Location' - def expectedResponseHeaderValue = "/api/MetadataResolver/$expectedMetadataResolverUUID/Filters/$expectedFilterUUID" + def expectedResponseHeaderValue = "$BASE_URI/$expectedMetadataResolverUUID/Filters/$expectedFilterUUID" def expectedJsonBody = mapper.writeValueAsString(randomFilter) def postedJsonBody = expectedJsonBody - ~/"id":.*?,/ // remove the "id:," println postedJsonBody @@ -148,7 +148,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( - post('/api/MetadataResolver/foo/Filters') + post("$BASE_URI/foo/Filters") .contentType(APPLICATION_JSON_UTF8) .content(postedJsonBody)) @@ -182,7 +182,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( - put("/api/MetadataResolver/foo/Filters/$filterUUID") + put("$BASE_URI/foo/Filters/$filterUUID") .contentType(APPLICATION_JSON_UTF8) .content(postedJsonBody)) @@ -212,7 +212,7 @@ class MetadataFiltersControllerTests extends Specification { when: def result = mockMvc.perform( - put("/api/MetadataResolver/foo/Filters/$filterUUID") + put("$BASE_URI/foo/Filters/$filterUUID") .contentType(APPLICATION_JSON_UTF8) .content(postedJsonBody)) From 6874aa096516428b45ecfc2713e7f514d4207b18 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Mon, 25 Jun 2018 16:13:55 -0400 Subject: [PATCH 09/17] SHIBUI-521(545): REST controller integration tests --- .../MetadataResolversController.java | 9 +- .../src/main/resources/application.properties | 2 + ...ResolversControllerIntegrationTests.groovy | 177 +++++++++++++++--- 3 files changed, 161 insertions(+), 27 deletions(-) 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 0078284e1..336e32d44 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 @@ -49,7 +49,7 @@ public ResponseEntity getOne(@PathVariable String resourceId) { @PostMapping("/MetadataResolvers") @Transactional public ResponseEntity create(@RequestBody MetadataResolver newResolver) { - //TODO: we are disregarding attached filters if any sent from UI below. + //TODO: we are disregarding attached filters if any sent from UI. //Only deal with filters via filters endpoints? newResolver.clearAllFilters(); @@ -62,8 +62,6 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) { @PutMapping("/MetadataResolvers/{resourceId}") @Transactional public ResponseEntity update(@PathVariable String resourceId, @RequestBody MetadataResolver updatedResolver) { - //TODO disregard attached filters if any sent from UI? - //Only deal with filters via filters endpoints? And here only update the resolver pieces?? MetadataResolver existingResolver = resolverRepository.findByResourceId(resourceId); if (existingResolver == null) { return ResponseEntity.notFound().build(); @@ -75,6 +73,11 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me } updatedResolver.setAudId(existingResolver.getAudId()); + + //TODO: we are disregarding attached filters if any sent from UI. + //Only deal with filters via filters endpoints? + updatedResolver.setMetadataFilters(existingResolver.getMetadataFilters()); + MetadataResolver persistedResolver = resolverRepository.save(updatedResolver); persistedResolver.updateVersion(); diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index ac9a01597..733962eb0 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -5,6 +5,8 @@ #logging.config=classpath:log4j2.xml #logging.level.org.springframework.web=ERROR +logging.level.edu.internet2.tier.shibboleth.admin.ui=INFO + # Database Credentials spring.datasource.username=shibui spring.datasource.password=shibui 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 a60e5a1ad..256285f94 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 @@ -1,10 +1,10 @@ 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.DynamicHttpMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import groovy.json.JsonOutput +import groovy.json.JsonSlurper import org.opensaml.saml.metadata.resolver.MetadataResolver import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver import org.springframework.beans.factory.annotation.Autowired @@ -12,16 +12,21 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.context.annotation.Bean +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders + import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ActiveProfiles import spock.lang.Specification -import javax.persistence.EntityManager +import static org.springframework.http.HttpMethod.PUT +/** + * @author Dmitriy Kopylenko + */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("no-auth") -@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class MetadataResolversControllerIntegrationTests extends Specification { @Autowired @@ -30,47 +35,171 @@ class MetadataResolversControllerIntegrationTests extends Specification { @Autowired MetadataResolverRepository metadataResolverRepository - @Autowired - EntityManager entityManager + JsonSlurper jsonSlurper = new JsonSlurper() - ObjectMapper mapper + static BASE_URI = '/api/MetadataResolvers' - def setup() { - mapper = new ObjectMapper() - mapper.registerModule(new JavaTimeModule()) - mapper.enable(SerializationFeature.INDENT_OUTPUT) + def cleanup() { + metadataResolverRepository.deleteAll() } - def "GET empty /api/MetadataResolvers"() { - when: - def result = this.restTemplate.getForEntity("/api/MetadataResolvers", String) - def returnedResolvers = mapper.readValue(result.body, - edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver[]) + def "GET empty -> /api/MetadataResolvers"() { + when: 'No resolvers are available in data store' + def result = this.restTemplate.getForEntity(BASE_URI, String) + def returnedResolvers = jsonSlurper.parseText(result.body) then: result.statusCodeValue == 200 returnedResolvers.size() == 0 } - def "GET one DynamicHttpMetadataResolver /api/MetadataResolvers"() { - given: + def "GET one available MetadataResolver -> /api/MetadataResolvers"() { + given: 'One resolver is available in data store' def resolver = new DynamicHttpMetadataResolver().with { it.name = 'Test DynamicHttpMetadataResolver' it } metadataResolverRepository.save(resolver) - when: - def result = this.restTemplate.getForEntity("/api/MetadataResolvers", String) - def returnedResolvers = mapper.readValue(result.body, - edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver[]) + when: 'GET request is made' + def result = this.restTemplate.getForEntity(BASE_URI, String) + def returnedResolvers = jsonSlurper.parseText(result.body) then: result.statusCodeValue == 200 returnedResolvers.size() == 1 - returnedResolvers[0] instanceof DynamicHttpMetadataResolver + returnedResolvers[0]['@type'] == 'DynamicHttpMetadataResolver' + returnedResolvers[0].name == 'Test DynamicHttpMetadataResolver' + + } + + def "GET multiple available MetadataResolvers -> /api/MetadataResolvers"() { + given: 'Two resolvers are available in data store' + def resolvers = [ + new DynamicHttpMetadataResolver().with { + it.name = 'Test DynamicHttpMetadataResolver' + it + }, + new FileBackedHttpMetadataResolver().with { + it.name = 'Test FileBackedHttpMetadataResolver' + it + } + ] + resolvers.each { + metadataResolverRepository.save(it) + } + + when: 'GET request is made' + def result = this.restTemplate.getForEntity(BASE_URI, String) + def returnedResolvers = jsonSlurper.parseText(result.body) + + then: + result.statusCodeValue == 200 + returnedResolvers.size() == 2 + returnedResolvers[0]['@type'] == 'DynamicHttpMetadataResolver' returnedResolvers[0].name == 'Test DynamicHttpMetadataResolver' + returnedResolvers[1]['@type'] == 'FileBackedHttpMetadataResolver' + returnedResolvers[1].name == 'Test FileBackedHttpMetadataResolver' + + } + + def "GET concrete MetadataResolver -> /api/MetadataResolvers/{resourceId}"() { + given: 'One resolver is available in data store' + def resolver = new DynamicHttpMetadataResolver().with { + it.name = 'Test DynamicHttpMetadataResolver' + it + } + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + when: 'GET request is made with resource Id matching the existing resolver' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId", String) + def returnedResolver = jsonSlurper.parseText(result.body) + + then: + result.statusCodeValue == 200 + returnedResolver['@type'] == 'DynamicHttpMetadataResolver' + returnedResolver.name == 'Test DynamicHttpMetadataResolver' + + } + + def "GET non-existent MetadataResolver -> /api/MetadataResolvers/{resourceId}"() { + when: 'GET request is made with resource Id not matching any resolvers' + def result = this.restTemplate.getForEntity("$BASE_URI/bogus-resource-id", String) + + then: + result.statusCodeValue == 404 + } + + def "POST new DynamicHttpMetadataResolver -> /api/MetadataResolvers"() { + given: 'New MetadataResolver JSON representation' + def resolver = [name: 'Test DynamicHttpMetadataResolver', '@type': 'DynamicHttpMetadataResolver'] + + when: 'POST request is made with new DynamicHttpMetadataResolver JSON representation' + def result = this.restTemplate.postForEntity(BASE_URI, createRequestHttpEntityFor { JsonOutput.toJson(resolver) }, String) + + then: + result.statusCodeValue == 201 + result.headers.Location[0].contains(BASE_URI) + } + + def "PUT concrete MetadataResolver with updated changes -> /api/MetadataResolvers/{resourceId}"() { + given: 'One resolver is available in data store' + def resolver = new DynamicHttpMetadataResolver().with { + it.name = 'Test DynamicHttpMetadataResolver' + it + } + def resolverResourceId = resolver.resourceId + metadataResolverRepository.save(resolver) + + when: 'GET request is made with resource Id matching the existing resolver' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId", String) + + and: 'Resolver data is updated and sent back to the server' + def metadataResolverMap = new JsonSlurper().parseText(result.body) + metadataResolverMap.name = 'Updated DynamicHttpMetadataResolver' + def updatedResult = this.restTemplate.exchange( + "$BASE_URI/${metadataResolverMap.resourceId}", + PUT, + createRequestHttpEntityFor { JsonOutput.toJson(metadataResolverMap) }, + String) + def updatedResolverMap = new JsonSlurper().parseText(updatedResult.body) + + then: + updatedResult.statusCodeValue == 200 + updatedResolverMap.name == 'Updated DynamicHttpMetadataResolver' + + } + + def "PUT concrete MetadataResolver with version conflict -> /api/MetadataResolvers/{resourceId}"() { + given: 'One resolver is available in data store' + def resolver = new DynamicHttpMetadataResolver().with { + it.name = 'Test DynamicHttpMetadataResolver' + it + } + def resolverResourceId = resolver.resourceId + def persistedResolver = metadataResolverRepository.save(resolver) + + when: 'GET request is made with resource Id matching the existing resolver' + def result = this.restTemplate.getForEntity("$BASE_URI/$resolverResourceId", String) + + and: 'Resolver data is updated and sent back to the server, but then original resolver is changed in data store' + persistedResolver.name = 'Some other name' + metadataResolverRepository.save(persistedResolver) + def metadataResolverMap = new JsonSlurper().parseText(result.body) + metadataResolverMap.name = 'Updated DynamicHttpMetadataResolver' + def updatedResult = this.restTemplate.exchange( + "$BASE_URI/${metadataResolverMap.resourceId}", + PUT, + createRequestHttpEntityFor { JsonOutput.toJson(metadataResolverMap) }, + String) + + then: + updatedResult.statusCodeValue == 409 + } + private HttpEntity createRequestHttpEntityFor(Closure jsonBodySupplier) { + new HttpEntity(jsonBodySupplier(), ['Content-Type': 'application/json'] as HttpHeaders) } @TestConfiguration From 9db33c6e6d519dccdd47a4950e7270d756900ff3 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 09:18:47 -0400 Subject: [PATCH 10/17] SHIBUI-521(544): domain model --- .../resolvers/ClasspathMetadataResource.java | 20 +++++++++++ .../ResourceBackedMetadataResolver.java | 26 ++++++++++++++ .../domain/resolvers/SvnMetadataResource.java | 34 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ClasspathMetadataResource.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/SvnMetadataResource.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ClasspathMetadataResource.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ClasspathMetadataResource.java new file mode 100644 index 000000000..a3dc076ab --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ClasspathMetadataResource.java @@ -0,0 +1,20 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Embeddable; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class ClasspathMetadataResource { + + private String file; +} 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 new file mode 100644 index 000000000..0958eba8b --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolver.java @@ -0,0 +1,26 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Embedded; +import javax.persistence.Entity; + +@Entity +@EqualsAndHashCode(callSuper = true) +@Getter +@Setter +@ToString +public class ResourceBackedMetadataResolver extends MetadataResolver { + + @Embedded + private ReloadableMetadataResolverAttributes reloadableMetadataResolverAttributes; + + @Embedded + private ClasspathMetadataResource classpathMetadataResource; + + @Embedded + private SvnMetadataResource svnMetadataResource; +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/SvnMetadataResource.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/SvnMetadataResource.java new file mode 100644 index 000000000..06f039bc6 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/SvnMetadataResource.java @@ -0,0 +1,34 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Embeddable; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class SvnMetadataResource { + + private String repositoryURL; + + private String workingCopyDirectory; + + private String resourceFile; + + private String username; + + private String password; + + private String proxyHost; + + private String proxyUserName; + + private String proxyPassword; +} From 551cec5ca62f6e0773d6f413d4814e89bda7f8bd Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 12:08:01 -0400 Subject: [PATCH 11/17] SHIBUI-521(622): metadata resolver validation facility wip... --- .../MetadataResolverValidationService.java | 27 ++++++ .../resolvers/MetadataResolverValidator.java | 25 +++++ .../ResourceBackedMetadataResolver.java | 32 ++++++- .../EntityAttributesFilterTargetTests.groovy | 2 +- ...ymorphicFiltersJacksonHandlingTests.groovy | 2 +- ...adataResolverValidationServiceTests.groovy | 93 +++++++++++++++++++ ...orphicResolversJacksonHandlingTests.groovy | 2 +- 7 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java rename backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/{ => filters}/EntityAttributesFilterTargetTests.groovy (93%) rename backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/{ => filters}/PolymorphicFiltersJacksonHandlingTests.groovy (99%) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceTests.groovy rename backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/{ => resolvers}/PolymorphicResolversJacksonHandlingTests.groovy (99%) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java new file mode 100644 index 000000000..f5c0932a7 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java @@ -0,0 +1,27 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator.ValidationResult; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class MetadataResolverValidationService { + + private List validators; + + public MetadataResolverValidationService(List validators) { + this.validators = validators != null ? validators : new ArrayList<>(); + } + + @SuppressWarnings("Uncheked") + public ValidationResult validateIfNecessary(T metadataResolver) { + Optional validator = + this.validators + .stream() + .filter(v -> v.supports(metadataResolver)) + .findFirst(); + return validator.isPresent() ? validator.get().validate(metadataResolver) : new ValidationResult(null); + + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java new file mode 100644 index 000000000..e5ccb66c0 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java @@ -0,0 +1,25 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +public interface MetadataResolverValidator { + + boolean supports(T resolver); + + ValidationResult validate(T resolver); + + class ValidationResult { + + public ValidationResult(String errorMessage) { + this.errorMessage = errorMessage; + } + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public boolean isValid() { + return this.errorMessage == null; + } + } +} 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 0958eba8b..422e46d57 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,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -7,9 +8,13 @@ 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; @Entity -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = true, exclude = "resourceType") @Getter @Setter @ToString @@ -23,4 +28,29 @@ public class ResourceBackedMetadataResolver extends MetadataResolver { @Embedded private SvnMetadataResource svnMetadataResource; + + @Transient + @JsonIgnore + private ResourceType resourceType; + + public void validateAndDetermineResourceType() throws InvalidResourceTypeException { + if (classpathMetadataResource == null && svnMetadataResource == null) { + throw new InvalidResourceTypeException("No metadata resource is provided. Exactly one is required"); + } + if (classpathMetadataResource != null && svnMetadataResource != null) { + throw new InvalidResourceTypeException("Too many metadata resources are provided. Exactly one is required"); + } + resourceType = classpathMetadataResource != null ? CLASSPATH : SVN; + } + + public class InvalidResourceTypeException extends IllegalStateException { + public InvalidResourceTypeException(String s) { + super(s); + } + } + + public enum ResourceType { + CLASSPATH, + SVN + } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityAttributesFilterTargetTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTargetTests.groovy similarity index 93% rename from backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityAttributesFilterTargetTests.groovy rename to backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTargetTests.groovy index cf4fd32eb..2ff346ee7 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityAttributesFilterTargetTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/EntityAttributesFilterTargetTests.groovy @@ -1,4 +1,4 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain +package edu.internet2.tier.shibboleth.admin.ui.domain.filters import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget import spock.lang.Specification diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicFiltersJacksonHandlingTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy similarity index 99% rename from backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicFiltersJacksonHandlingTests.groovy rename to backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy index 4e5899f49..56112a350 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicFiltersJacksonHandlingTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/filters/PolymorphicFiltersJacksonHandlingTests.groovy @@ -1,4 +1,4 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain +package edu.internet2.tier.shibboleth.admin.ui.domain.filters import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceTests.groovy new file mode 100644 index 000000000..d62f07170 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceTests.groovy @@ -0,0 +1,93 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers + +import spock.lang.Specification +import spock.lang.Subject + +import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator.* + +/** + * @author Dmitriy Kopylenko + */ +class MetadataResolverValidationServiceTests extends Specification { + + def "Validation service with no available validators always returns default valid result"() { + given: 'Sample metadata resolver and validation service with no validators' + def resolver = Mock(MetadataResolver) + @Subject + def validationService = new MetadataResolverValidationService(null) + + when: 'Validation call is made' + def validationResult = validationService.validateIfNecessary(resolver) + + then: + validationResult.valid + } + + def "Validation service with one validator not supporting the type of resolver returns default valid result"() { + given: 'Sample metadata resolver and validation service with one validator not supporting that type' + def resolver = Mock(MetadataResolver) + def validator = Mock(MetadataResolverValidator) + validator.supports(_) >> false + @Subject + def validationService = new MetadataResolverValidationService([validator]) + + when: 'Validation call is made' + def validationResult = validationService.validateIfNecessary(resolver) + + then: + validationResult.valid + } + + def "Validation service with one validator supporting the type of resolver but fails its validation"() { + given: 'Sample metadata resolver and validation service with one validator supporting that type' + def resolver = Mock(MetadataResolver) + def validator = Mock(MetadataResolverValidator) + validator.supports(_) >> true + validator.validate(_) >> new ValidationResult('Invalid') + @Subject + def validationService = new MetadataResolverValidationService([validator]) + + when: 'Validation call is made' + def validationResult = validationService.validateIfNecessary(resolver) + + then: + !validationResult.valid + } + + def "Validation service with with two validators supporting the type of resolver, first fails, second passes validation"() { + given: 'Sample metadata resolver and validation service with two validators supporting that type' + def resolver = Mock(MetadataResolver) + def validator1 = Mock(MetadataResolverValidator) + validator1.supports(_) >> true + validator1.validate(_) >> new ValidationResult('Invalid') + def validator2 = Mock(MetadataResolverValidator) + validator2.supports(_) >> true + validator2.validate(_) >> new ValidationResult(null) + @Subject + def validationService = new MetadataResolverValidationService([validator1, validator2]) + + when: 'Validation call is made' + def validationResult = validationService.validateIfNecessary(resolver) + + then: 'Result depends on list order of validators if all of them support the resolver type. This would be considered a mis-configuration' + !validationResult.valid + } + + def "Validation service with with two validators, only one supporting the type of resolver, passes validation"() { + given: 'Sample metadata resolver and validation service with two validators, with one supporting that type' + def resolver = Mock(MetadataResolver) + def validator1 = Mock(MetadataResolverValidator) + validator1.supports(_) >> false + def validator2 = Mock(MetadataResolverValidator) + validator2.supports(_) >> true + validator2.validate(_) >> new ValidationResult(null) + @Subject + def validationService = new MetadataResolverValidationService([validator1, validator2]) + + when: 'Validation call is made' + def validationResult = validationService.validateIfNecessary(resolver) + + then: + validationResult.valid + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy similarity index 99% rename from backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy rename to backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy index 2ed5eda32..869f4465f 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/PolymorphicResolversJacksonHandlingTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy @@ -1,4 +1,4 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature From 9bfef72486276ea61e02f60e5023296325314dff Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 12:19:58 -0400 Subject: [PATCH 12/17] SHIBUI-521(622) wip --- .../resolvers/MetadataResolverValidationService.java | 8 ++++++++ .../ui/domain/resolvers/MetadataResolverValidator.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java index f5c0932a7..3c16e183d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java @@ -6,6 +6,14 @@ import java.util.List; import java.util.Optional; +/** + * A facade that aggregates {@link MetadataResolverValidator}s available to call just one of them supporting the type of a given resolver. + * If no {@link MetadataResolverValidator}s are configured, conciders provided MetadataResolver as valid. + *

+ * Uses chain-of-responsibility design pattern + * + * @author Dmitriy Kopylenko + */ public class MetadataResolverValidationService { private List validators; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java index e5ccb66c0..f64ab96d6 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java @@ -1,5 +1,14 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; +/** + * An SPI to validate different types of {@link MetadataResolver}s. + *

+ * Typical usage is - multiple validators for concrete type of resolvers are configured in Spring Application Context, + * aggregated by {@link MetadataResolverValidationService} facade and then that facade is injected into upstream consumers of it + * such as REST controllers, etc. + * + * @author Dmitriy Kopylenko + */ public interface MetadataResolverValidator { boolean supports(T resolver); From 01b839770dce746abef88d2444e068a224fb1e17 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 17:00:00 -0400 Subject: [PATCH 13/17] SHIBUI-521(622): Validation facility wip --- .../MetadataResolverValidationService.java | 11 ++-- .../resolvers/MetadataResolverValidator.java | 2 +- .../ResourceBackedMetadataResolver.java | 8 +-- ...sourceBackedMetadataResolverValidator.java | 20 +++++++ ...dataResolverValidationConfiguration.groovy | 29 +++++++++++ ...ResolversControllerIntegrationTests.groovy | 1 - ...ValidationServiceConfigurationTests.groovy | 29 +++++++++++ ...esourceBackedMetadataValidatorTests.groovy | 52 +++++++++++++++++++ 8 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolverValidator.java create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataValidatorTests.groovy diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java index 3c16e183d..26039b81b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationService.java @@ -16,15 +16,15 @@ */ public class MetadataResolverValidationService { - private List validators; + private List> validators; - public MetadataResolverValidationService(List validators) { + public MetadataResolverValidationService(List> validators) { this.validators = validators != null ? validators : new ArrayList<>(); } @SuppressWarnings("Uncheked") public ValidationResult validateIfNecessary(T metadataResolver) { - Optional validator = + Optional> validator = this.validators .stream() .filter(v -> v.supports(metadataResolver)) @@ -32,4 +32,9 @@ public ValidationResult validateIfNecessary(T metadataResolver) { return validator.isPresent() ? validator.get().validate(metadataResolver) : new ValidationResult(null); } + + //Package-private - used for unit tests + boolean noValidatorsConfigured() { + return this.validators.size() == 0; + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java index f64ab96d6..e6afc7782 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidator.java @@ -11,7 +11,7 @@ */ public interface MetadataResolverValidator { - boolean supports(T resolver); + boolean supports(MetadataResolver resolver); ValidationResult validate(T resolver); 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 422e46d57..bbb41d357 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 @@ -29,18 +29,14 @@ public class ResourceBackedMetadataResolver extends MetadataResolver { @Embedded private SvnMetadataResource svnMetadataResource; - @Transient - @JsonIgnore - private ResourceType resourceType; - - public void validateAndDetermineResourceType() throws InvalidResourceTypeException { + public ResourceType validateAndDetermineResourceType() throws InvalidResourceTypeException { if (classpathMetadataResource == null && svnMetadataResource == null) { throw new InvalidResourceTypeException("No metadata resource is provided. Exactly one is required"); } if (classpathMetadataResource != null && svnMetadataResource != null) { throw new InvalidResourceTypeException("Too many metadata resources are provided. Exactly one is required"); } - resourceType = classpathMetadataResource != null ? CLASSPATH : SVN; + return classpathMetadataResource != null ? CLASSPATH : SVN; } public class InvalidResourceTypeException extends IllegalStateException { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolverValidator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolverValidator.java new file mode 100644 index 000000000..0a828fbed --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataResolverValidator.java @@ -0,0 +1,20 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +public class ResourceBackedMetadataResolverValidator implements MetadataResolverValidator { + + @Override + public boolean supports(MetadataResolver resolver) { + return resolver instanceof ResourceBackedMetadataResolver; + } + + @Override + public ValidationResult validate(ResourceBackedMetadataResolver resolver) { + try { + resolver.validateAndDetermineResourceType(); + } + catch (ResourceBackedMetadataResolver.InvalidResourceTypeException e) { + return new ValidationResult(e.getMessage()); + } + return new ValidationResult(null); + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy new file mode 100644 index 000000000..d3493a06f --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidationService +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolverValidator + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + + +@Configuration +class TestMetadataResolverValidationServiceConfiguration { + + @Bean + ResourceBackedMetadataResolverValidator resourceBackedMetadataResolverValidator() { + new ResourceBackedMetadataResolverValidator() + } + + @Bean + MetadataResolverValidationService metadataResolverValidationServiceEmpty() { + new MetadataResolverValidationService(null) + } + + @Bean + MetadataResolverValidationService metadataResolverValidationServiceOneValidator(List metadataResolverValidators) { + new MetadataResolverValidationService(metadataResolverValidators) + } + +} 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 256285f94..81408eafd 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 @@ -15,7 +15,6 @@ import org.springframework.context.annotation.Bean import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ActiveProfiles import spock.lang.Specification diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy new file mode 100644 index 000000000..6ca9c4182 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers + +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestMetadataResolverValidationServiceConfiguration +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.test.context.ContextConfiguration +import spock.lang.Specification + +@ContextConfiguration(classes=[TestMetadataResolverValidationServiceConfiguration]) +class MetadataResolverValidationServiceConfigurationTests extends Specification { + + @Autowired + @Qualifier("metadataResolverValidationServiceEmpty") + MetadataResolverValidationService metadataResolverValidationServiceNoValidators + + @Autowired + @Qualifier("metadataResolverValidationServiceOneValidator") + MetadataResolverValidationService metadataResolverValidationServiceOneValidator + + def "Validation service with no validators"() { + expect: + metadataResolverValidationServiceNoValidators.noValidatorsConfigured() + } + + def "Validation service with one validator"() { + expect: + !metadataResolverValidationServiceOneValidator.noValidatorsConfigured() + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataValidatorTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataValidatorTests.groovy new file mode 100644 index 000000000..6447a7f1a --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ResourceBackedMetadataValidatorTests.groovy @@ -0,0 +1,52 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers + +import spock.lang.Specification + +class ResourceBackedMetadataValidatorTests extends Specification { + + def "Does not support foreign resolver type"() { + given: + MetadataResolverValidator validator = new ResourceBackedMetadataResolverValidator() + FileBackedHttpMetadataResolver resolver = new FileBackedHttpMetadataResolver() + + expect: + !validator.supports(resolver) + } + + def "Passes validation"() { + given: + MetadataResolverValidator validator = new ResourceBackedMetadataResolverValidator() + ResourceBackedMetadataResolver resolver = new ResourceBackedMetadataResolver().with { + it.classpathMetadataResource = new ClasspathMetadataResource() + it + } + + expect: + validator.supports(resolver) + validator.validate(resolver).valid + } + + def "Does not pass validation with both resource types missing"() { + given: + MetadataResolverValidator validator = new ResourceBackedMetadataResolverValidator() + ResourceBackedMetadataResolver resolver = new ResourceBackedMetadataResolver() + + expect: + validator.supports(resolver) + !validator.validate(resolver).valid + } + + def "Does not pass validation with both resource types present"() { + given: + MetadataResolverValidator validator = new ResourceBackedMetadataResolverValidator() + ResourceBackedMetadataResolver resolver = new ResourceBackedMetadataResolver().with { + it.classpathMetadataResource = new ClasspathMetadataResource() + it.svnMetadataResource = new SvnMetadataResource() + it + } + + expect: + validator.supports(resolver) + !validator.validate(resolver).valid + } +} From 94d615d934e0e117d05f9e63a9efb560faf2d0ac Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 17:41:12 -0400 Subject: [PATCH 14/17] SHIBUI-521(622) --- ...tadataResolverValidationConfiguration.java | 24 ++++++++++++++++ .../MetadataResolversController.java | 28 ++++++++++++++++++- ...dataResolverValidationConfiguration.groovy | 2 +- ...ResolversControllerIntegrationTests.groovy | 5 +++- ...ValidationServiceConfigurationTests.groovy | 7 +++-- 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java new file mode 100644 index 000000000..e8229f8d8 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java @@ -0,0 +1,24 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidationService; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolverValidator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +public class MetadataResolverValidationConfiguration { + + //@Bean + ResourceBackedMetadataResolverValidator resourceBackedMetadataResolverValidator() { + return new ResourceBackedMetadataResolverValidator(); + } + + @Bean + @SuppressWarnings("Unchecked") + MetadataResolverValidationService metadataResolverValidationService(List metadataResolverValidators) { + return new MetadataResolverValidationService(metadataResolverValidators); + } +} 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 336e32d44..ae75b3f6d 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 @@ -1,8 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.controller; 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.MetadataResolverValidator; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; -import lombok.extern.log4j.Log4j; + import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -19,6 +21,8 @@ import java.net.URI; +import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolverValidator.ValidationResult; + @RestController @RequestMapping("/api") @Slf4j @@ -27,6 +31,9 @@ public class MetadataResolversController { @Autowired MetadataResolverRepository resolverRepository; + @Autowired + MetadataResolverValidationService metadataResolverValidationService; + @GetMapping("/MetadataResolvers") @Transactional(readOnly = true) public ResponseEntity getAll() { @@ -53,6 +60,11 @@ public ResponseEntity create(@RequestBody MetadataResolver newResolver) { //Only deal with filters via filters endpoints? newResolver.clearAllFilters(); + ResponseEntity validationErrorResponse = validate(newResolver); + if(validationErrorResponse != null) { + return validationErrorResponse; + } + MetadataResolver persistedResolver = resolverRepository.save(newResolver); persistedResolver.updateVersion(); @@ -72,6 +84,11 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me return ResponseEntity.status(HttpStatus.CONFLICT).build(); } + ResponseEntity validationErrorResponse = validate(updatedResolver); + if(validationErrorResponse != null) { + return validationErrorResponse; + } + updatedResolver.setAudId(existingResolver.getAudId()); //TODO: we are disregarding attached filters if any sent from UI. @@ -84,6 +101,15 @@ public ResponseEntity update(@PathVariable String resourceId, @RequestBody Me return ResponseEntity.ok(persistedResolver); } + @SuppressWarnings("Unchecked") + private ResponseEntity validate(MetadataResolver metadataResolver) { + ValidationResult validationResult = metadataResolverValidationService.validateIfNecessary(metadataResolver); + if(!validationResult.isValid()) { + return ResponseEntity.badRequest().body(validationResult.getErrorMessage()); + } + return null; + } + private static URI getResourceUriFor(MetadataResolver resolver) { return ServletUriComponentsBuilder .fromCurrentServletMapping().path("/api/MetadataResolvers/") diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy index d3493a06f..d5c2f4f29 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestMetadataResolverValidationConfiguration.groovy @@ -9,7 +9,7 @@ import org.springframework.context.annotation.Configuration @Configuration -class TestMetadataResolverValidationServiceConfiguration { +class TestMetadataResolverValidationConfiguration { @Bean ResourceBackedMetadataResolverValidator resourceBackedMetadataResolverValidator() { 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 81408eafd..03ae982a5 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 @@ -162,10 +162,13 @@ class MetadataResolversControllerIntegrationTests extends Specification { PUT, createRequestHttpEntityFor { JsonOutput.toJson(metadataResolverMap) }, String) + then: + updatedResult.statusCodeValue == 200 + + and: def updatedResolverMap = new JsonSlurper().parseText(updatedResult.body) then: - updatedResult.statusCodeValue == 200 updatedResolverMap.name == 'Updated DynamicHttpMetadataResolver' } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy index 6ca9c4182..9007cb15e 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverValidationServiceConfigurationTests.groovy @@ -1,12 +1,15 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers -import edu.internet2.tier.shibboleth.admin.ui.configuration.TestMetadataResolverValidationServiceConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestMetadataResolverValidationConfiguration import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier import org.springframework.test.context.ContextConfiguration import spock.lang.Specification -@ContextConfiguration(classes=[TestMetadataResolverValidationServiceConfiguration]) +/** + * @author Dmitriy Kopylenko + */ +@ContextConfiguration(classes=[TestMetadataResolverValidationConfiguration]) class MetadataResolverValidationServiceConfigurationTests extends Specification { @Autowired From bc79e1cb0c18894fff82b6eb6e819829959bf761 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 17:58:29 -0400 Subject: [PATCH 15/17] Polishing --- .../configuration/MetadataResolverValidationConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java index e8229f8d8..6957f71b1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverValidationConfiguration.java @@ -11,7 +11,7 @@ @Configuration public class MetadataResolverValidationConfiguration { - //@Bean + @Bean ResourceBackedMetadataResolverValidator resourceBackedMetadataResolverValidator() { return new ResourceBackedMetadataResolverValidator(); } From 66dcaba292983ff2df65c8e020df0a343508f1bf Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 27 Jun 2018 15:50:56 -0400 Subject: [PATCH 16/17] SHIBUI-521(546): xml rendering and unit tests --- .../JPAMetadataResolverServiceImpl.groovy | 49 +++++++++++++++++++ .../ResourceBackedMetadataResolver.java | 2 - ...JPAMetadataResolverServiceImplTests.groovy | 9 +++- ...JPAMetadataResolverServiceImplTests.groovy | 46 ++++++++++++++++- .../admin/ui/util/TestObjectGenerator.groovy | 13 +++++ backend/src/test/resources/conf/278.2.xml | 8 +++ backend/src/test/resources/conf/278.xml | 8 +++ .../src/test/resources/conf/546-classpath.xml | 13 +++++ backend/src/test/resources/conf/546-svn.xml | 16 ++++++ 9 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 backend/src/test/resources/conf/546-classpath.xml create mode 100644 backend/src/test/resources/conf/546-svn.xml 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 @@ + + + + + + + + From fdf5da0e01a7c8fdf47169331fdcc136945a8c73 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 27 Jun 2018 18:09:45 -0400 Subject: [PATCH 17/17] SHIBUI-521: tests memory usage tuning which speeds up test run and fixes OOM experienced locally --- .../ResourceBackedMetadataResolver.java | 2 +- ...faultAuthenticationIntegrationTests.groovy | 34 ++----------------- ...HttpMetadataProviderControllerTests.groovy | 3 +- .../EntitiesControllerIntegrationTests.groovy | 2 ++ ...amicMetadataProviderControllerTests.groovy | 3 +- ...orphicResolversJacksonHandlingTests.groovy | 6 ---- .../EnityDescriptorRepositoryTest.groovy | 3 +- ...HttpMetadataResolverRepositoryTests.groovy | 1 + .../repository/FilterRepositoryTests.groovy | 6 ++-- ...amicMetadataResolverRepositoryTests.groovy | 6 ++-- .../MetadataResolverRepositoryTests.groovy | 6 ++-- ...JPAMetadataResolverServiceImplTests.groovy | 1 + 12 files changed, 18 insertions(+), 55 deletions(-) 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 6e60ebf5b..2133d88eb 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 @@ -12,7 +12,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ResourceBackedMetadataResolver.ResourceType.SVN; @Entity -@EqualsAndHashCode(callSuper = true, exclude = "resourceType") +@EqualsAndHashCode(callSuper = true) @Getter @Setter @ToString diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DefaultAuthenticationIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DefaultAuthenticationIntegrationTests.groovy index c70e6f44f..946413ab5 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DefaultAuthenticationIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DefaultAuthenticationIntegrationTests.groovy @@ -1,17 +1,11 @@ package edu.internet2.tier.shibboleth.admin.ui.controller -import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects -import net.shibboleth.ext.spring.resource.ResourceHelper -import org.joda.time.DateTime -import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver -import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain -import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver +import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean -import org.springframework.core.io.ClassPathResource import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.web.util.DefaultUriBuilderFactory @@ -46,33 +40,9 @@ class DefaultAuthenticationIntegrationTests extends Specification { @TestConfiguration static class Config { - @Autowired - OpenSamlObjects openSamlObjects - @Bean MetadataResolver metadataResolver() { - def resource = ResourceHelper.of(new ClassPathResource("/metadata/aggregate.xml")) - def aggregate = new ResourceBackedMetadataResolver(resource){ - @Override - DateTime getLastRefresh() { - return null - } - } - - aggregate.with { - it.metadataFilter = new MetadataFilterChain() - it.id = 'testme' - it.parserPool = openSamlObjects.parserPool - it.initialize() - it - } - - return new ChainingMetadataResolver().with { - it.id = 'chain' - it.resolvers = [aggregate] - it.initialize() - it - } + new FilesystemMetadataResolver(new File('fake')) } } } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DynamicHttpMetadataProviderControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DynamicHttpMetadataProviderControllerTests.groovy index bf4ce2ffe..5b10c9f6e 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DynamicHttpMetadataProviderControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/DynamicHttpMetadataProviderControllerTests.groovy @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration import edu.internet2.tier.shibboleth.admin.ui.repository.DynamicHttpMetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator @@ -27,7 +28,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Bill Smith (wsmith@unicon.net) */ @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") class DynamicHttpMetadataProviderControllerTests extends Specification { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy index 2ed405784..33a407f1a 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy @@ -6,6 +6,7 @@ import org.joda.time.DateTime import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain +import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -147,6 +148,7 @@ class EntitiesControllerIntegrationTests extends Specification { !diff.hasDifferences() } + @TestConfiguration static class Config { @Autowired diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/LocalDynamicMetadataProviderControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/LocalDynamicMetadataProviderControllerTests.groovy index bc13df607..14c925c5c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/LocalDynamicMetadataProviderControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/LocalDynamicMetadataProviderControllerTests.groovy @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration import edu.internet2.tier.shibboleth.admin.ui.repository.LocalDynamicMetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator @@ -27,7 +28,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Bill Smith (wsmith@unicon.net) */ @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") class LocalDynamicMetadataProviderControllerTests extends Specification { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy index 869f4465f..79962f546 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/PolymorphicResolversJacksonHandlingTests.groovy @@ -4,12 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityRoleWhiteListFilter -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.HttpMetadataResolverAttributes -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.domain.resolvers.ReloadableMetadataResolverAttributes import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import edu.internet2.tier.shibboleth.admin.util.AttributeUtility diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EnityDescriptorRepositoryTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EnityDescriptorRepositoryTest.groovy index 8935e2eac..e10ff5b0b 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EnityDescriptorRepositoryTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EnityDescriptorRepositoryTest.groovy @@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.test.annotation.DirtiesContext + import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @@ -24,7 +24,6 @@ import javax.persistence.EntityManager @ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class EnityDescriptorRepositoryTest extends Specification { @Autowired EntityDescriptorRepository entityDescriptorRepository diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy index 619b650f9..5b5d90357 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy @@ -84,6 +84,7 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { // I suspect similar weirdness if httpMetadataResolverAttributes is an empty object, too. def resolverJson = '''{ "name": "name", + "@type": "FileBackedHttpMetadataResolver", "requireValidMetadata": true, "failFastInitialization": true, "sortKey": 7, diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy index 62b13ca8b..3ef170b9d 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FilterRepositoryTests.groovy @@ -2,24 +2,22 @@ package edu.internet2.tier.shibboleth.admin.ui.repository import com.fasterxml.jackson.databind.ObjectMapper import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration -import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilter import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import spock.lang.Specification import javax.persistence.EntityManager @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class FilterRepositoryTests extends Specification { @Autowired diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/LocalDynamicMetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/LocalDynamicMetadataResolverRepositoryTests.groovy index 027b9c030..039f3b324 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/LocalDynamicMetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/LocalDynamicMetadataResolverRepositoryTests.groovy @@ -1,8 +1,8 @@ package edu.internet2.tier.shibboleth.admin.ui.repository import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration -import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration 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.resolvers.DynamicMetadataResolverAttributes @@ -11,7 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @@ -20,10 +19,9 @@ import javax.persistence.EntityManager import static edu.internet2.tier.shibboleth.admin.ui.domain.filters.EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class LocalDynamicMetadataResolverRepositoryTests extends Specification { @Autowired diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy index 0d4ffd64a..7179dceee 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepositoryTests.groovy @@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @@ -30,7 +29,6 @@ import javax.persistence.EntityManager @ContextConfiguration(classes = [CoreShibUiConfiguration, SearchConfiguration, TestConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") -@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class MetadataResolverRepositoryTests extends Specification { @Autowired MetadataResolverRepository metadataResolverRepository @@ -216,8 +214,8 @@ class MetadataResolverRepositoryTests extends Specification { assert item.metadataFilters.get(0).entityAttributesFilterTarget.value.get(0) == "hola" } - private MetadataResolver create(Closure concreteResolverProvider) { - MetadataResolver resolver = concreteResolverProvider() + private MetadataResolver create(Closure concreteResolverSupplier) { + MetadataResolver resolver = concreteResolverSupplier() resolver.with { it.name = "testme" it.metadataFilters.add(new EntityAttributesFilter().with { 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 59a980423..03b737da9 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 @@ -44,6 +44,7 @@ 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