From 81a6359ac4e9d3e74b9739b9c5e0f9eeaeef1a7d Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 17 May 2018 16:59:31 -0400 Subject: [PATCH 1/7] [SHIBUI-517]: SHIBUI-528 JPA model --- .../JPAMetadataResolverServiceImpl.groovy | 4 +- .../MetadataResolverConfiguration.java | 2 +- .../admin/ui/controller/FilterController.java | 2 +- .../admin/ui/domain/MetadataResolver.java | 53 ------------------ .../FileBackedHttpMetadataResolver.java | 26 +++++++++ .../HttpMetadataResolverAttributes.java | 56 +++++++++++++++++++ .../ui/domain/resolvers/MetadataResolver.java | 48 ++++++++++++++++ .../ReloadableMetadataResolverAttributes.java | 33 +++++++++++ .../MetadataResolverRepository.java | 4 +- .../controller/FilterControllerTests.groovy | 2 +- .../MetadataResolverRepositoryTest.groovy | 2 +- ...JPAMetadataResolverServiceImplTests.groovy | 5 +- ...JPAMetadataResolverServiceImplTests.groovy | 3 +- 13 files changed, 173 insertions(+), 67 deletions(-) delete mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MetadataResolver.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java 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 da474a717..f28480e73 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 @@ -40,7 +40,7 @@ public class JPAMetadataResolverServiceImpl implements MetadataResolverService { // MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().stream().filter(r -> r.getId().equals(metadataResolverName)).findFirst().get(); MetadataResolver targetMetadataResolver = chainingMetadataResolver.getResolvers().find { it.id == metadataResolverName } - edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByName(metadataResolverName); + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver jpaMetadataResolver = metadataResolverRepository.findByName(metadataResolverName); if (targetMetadataResolver && targetMetadataResolver.getMetadataFilter() instanceof MetadataFilterChain) { MetadataFilterChain metadataFilterChain = (MetadataFilterChain)targetMetadataResolver.getMetadataFilter(); @@ -88,7 +88,7 @@ public class JPAMetadataResolverServiceImpl implements MetadataResolverService { 'xsi:type': 'ChainingMetadataProvider', 'xsi:schemaLocation': 'urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd urn:mace:shibboleth:2.0:resource http://shibboleth.net/schema/idp/shibboleth-resource.xsd urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd' ) { - metadataResolverRepository.findAll().each { edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver mr -> + metadataResolverRepository.findAll().each { edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr -> MetadataProvider(id: 'HTTPMetadata', 'xsi:type': 'FileBackedHTTPMetadataProvider', backingFile: '%{idp.home}/metadata/incommonmd.xml', diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java index f6a88b27d..51ba89b05 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java @@ -95,7 +95,7 @@ protected void processConditionalRetrievalHeaders(HttpResponse response) { resolvers.add(incommonMR); if (!metadataResolverRepository.findAll().iterator().hasNext()) { - edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver mr = new edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver(); + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver(); mr.setName("incommonmd"); metadataResolverRepository.save(mr); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FilterController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FilterController.java index 093a5b9ff..71db1e409 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FilterController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FilterController.java @@ -2,7 +2,7 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter; import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataFilter; -import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.FilterRepresentation; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; import edu.internet2.tier.shibboleth.admin.ui.service.FilterService; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MetadataResolver.java deleted file mode 100644 index 9d5288dbc..000000000 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/MetadataResolver.java +++ /dev/null @@ -1,53 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain; - -import lombok.EqualsAndHashCode; - -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.OneToMany; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -@Entity -@EqualsAndHashCode(callSuper = true) -public class MetadataResolver extends AbstractAuditable { - private String name; - private String resourceId = UUID.randomUUID().toString(); - - @OneToMany(cascade = CascadeType.ALL) - private List metadataFilters = new ArrayList<>(); - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - public List getMetadataFilters() { - return metadataFilters; - } - - public void setMetadataFilters(List metadataFilters) { - this.metadataFilters = metadataFilters; - } - - @Override - public String toString() { - return "MetadataResolver{\n" + - "name='" + name + "\'\n" + - ", resourceId='" + resourceId + "\'\n" + - ", metadataFilters=\n" + metadataFilters + - '}'; - } -} 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 new file mode 100644 index 000000000..c9850ecc6 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/FileBackedHttpMetadataResolver.java @@ -0,0 +1,26 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Embedded; +import javax.persistence.Entity; + +@Entity +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Getter +@Setter +@ToString +public class FileBackedHttpMetadataResolver extends MetadataResolver { + + @Embedded + private ReloadableMetadataResolverAttributes reloadableMetadataResolverAttributes; + + @Embedded + private HttpMetadataResolverAttributes httpMetadataResolverAttributes; + +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java new file mode 100644 index 000000000..a3d9d2c80 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java @@ -0,0 +1,56 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Enumerated; + +import static javax.persistence.EnumType.STRING; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class HttpMetadataResolverAttributes { + + private String httpClientRef; + + private String connectionRequestTimeout; + + private String requestTimeout; + + private String socketTimeout; + + private Boolean disregardTLSCertificate; + + private String tlsTrustEngineRef; + + private String httpClientSecurityParametersRef; + + private String proxyHost; + + private String proxyPort; + + private String proxyUser; + + private String proxyPassword; + + @Enumerated(STRING) + @Column(length = 5) + private HttpCachingType httpCaching; + + private String httpCacheDirectory; + + private Integer httpMaxCacheEntries; + + private Integer httpMaxCacheEntrySize; + + private enum HttpCachingType { + none,file,memory + } +} 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 new file mode 100644 index 000000000..e211cb27d --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolver.java @@ -0,0 +1,48 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import edu.internet2.tier.shibboleth.admin.ui.domain.AbstractAuditable; +import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataFilter; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +import javax.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Entity +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Getter +@Setter +@ToString +public class MetadataResolver extends AbstractAuditable { + + private String name; + + private String resourceId = UUID.randomUUID().toString(); + + private Boolean requireValidMetadata; + + private Boolean failFastInitialization; + + private Integer sortKey; + + private String criterionPredicateRegistryRef; + + private Boolean useDefaultPredicateRegistry; + + private Boolean satisfyAnyPredicates; + + @OneToMany(cascade = CascadeType.ALL) + private List metadataFilters = new ArrayList<>(); +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java new file mode 100644 index 000000000..ad21f7a23 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java @@ -0,0 +1,33 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Embeddable; + +@Embeddable +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ReloadableMetadataResolverAttributes { + + private String parserPoolRef; + + private String taskTimerRef; + + private String minRefreshDelay; + + private String maxRefreshDelay; + + private Double refreshDelayFactor; + + private String indexesRef; + + private Boolean resolveViaPredicatesOnly; + + private String expirationWarningThreshold; + +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepository.java index 5dba01872..fc415aef1 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepository.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/MetadataResolverRepository.java @@ -1,10 +1,10 @@ package edu.internet2.tier.shibboleth.admin.ui.repository; -import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import org.springframework.data.repository.CrudRepository; /** - * Repository to manage {@link edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver} instances. + * Repository to manage {@link MetadataResolver} instances. */ public interface MetadataResolverRepository extends CrudRepository { MetadataResolver findByName(String name); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FilterControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FilterControllerTests.groovy index fdf90d65d..9d8a1f72c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FilterControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FilterControllerTests.groovy @@ -5,7 +5,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfigurat 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.domain.EntityAttributesFilter -import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.service.FilterService import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService 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/MetadataResolverRepositoryTest.groovy index 713471f48..06584b52c 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/MetadataResolverRepositoryTest.groovy @@ -5,7 +5,7 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConf import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget -import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest 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 12112d0b9..7628f30de 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 @@ -4,14 +4,11 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfigurat import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget -import edu.internet2.tier.shibboleth.admin.ui.domain.MetadataFilter import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository import edu.internet2.tier.shibboleth.admin.util.AttributeUtility -import org.apache.http.impl.client.HttpClients import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver import org.opensaml.saml.metadata.resolver.MetadataResolver -import org.opensaml.saml.metadata.resolver.impl.FileBackedHTTPMetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest @@ -100,7 +97,7 @@ class IncommonJPAMetadataResolverServiceImplTests extends Specification { } if (!metadataResolverRepository.findAll().iterator().hasNext()) { - edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver mr = new edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver() + edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver mr = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver() mr.setName("incommonmd") metadataResolverRepository.save(mr) } 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 faa913f6b..afc93df62 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 @@ -1,7 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.service import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration -import edu.internet2.tier.shibboleth.admin.ui.configuration.MetadataResolverConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilter import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget @@ -75,7 +74,7 @@ class JPAMetadataResolverServiceImplTests extends Specification { ''' when: - def mdr = new edu.internet2.tier.shibboleth.admin.ui.domain.MetadataResolver().with { + def mdr = new edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver().with { it.name = "testme" it.metadataFilters.add(new EntityAttributesFilter().with { it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { From e1e8fcc1d9e5b3209ffb70ea9a6914dad211df05 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Fri, 18 May 2018 15:17:06 -0400 Subject: [PATCH 2/7] [SHIBUI-517]: SHIBUI-528 --- .../HttpMetadataResolverAttributes.java | 2 +- ...eBackedHttpMetadataResolverRepository.java | 12 ++++ ...HttpMetadataResolverRepositoryTests.groovy | 67 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java index a3d9d2c80..cc880cc32 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java @@ -41,7 +41,7 @@ public class HttpMetadataResolverAttributes { private String proxyPassword; @Enumerated(STRING) - @Column(length = 5) + @Column(length = 6) private HttpCachingType httpCaching; private String httpCacheDirectory; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java new file mode 100644 index 000000000..c4adea391 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java @@ -0,0 +1,12 @@ +package edu.internet2.tier.shibboleth.admin.ui.repository; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver; +import org.springframework.data.repository.CrudRepository; + +/** + * Spring Data CRUD repository for instances of {@link FileBackedHttpMetadataResolver}s. + */ +public interface FileBackedHttpMetadataResolverRepository extends CrudRepository { + + FileBackedHttpMetadataResolver findByName(String name); +} 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 new file mode 100644 index 000000000..710a966d3 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepositoryTests.groovy @@ -0,0 +1,67 @@ +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.domain.EntityAttributesFilter +import edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget +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.ReloadableMetadataResolverAttributes +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.context.ContextConfiguration +import spock.lang.Specification + +import static edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget.EntityAttributesFilterTargetType.* +import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes.HttpCachingType.memory + +@DataJpaTest +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +class FileBackedHttpMetadataResolverRepositoryTests extends Specification { + + @Autowired + FileBackedHttpMetadataResolverRepository repositoryUnderTest + + def "file backed http metadata resolver instances persist OK"() { + when: + def mdr = new FileBackedHttpMetadataResolver().with { + it.name = "FileBackedHttpMetadata" + it.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes() + it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes() + + it.httpMetadataResolverAttributes.connectionRequestTimeout = "PT05" + it.httpMetadataResolverAttributes.disregardTLSCertificate = true + it.httpMetadataResolverAttributes.httpCaching = memory + it.reloadableMetadataResolverAttributes.indexesRef = "indexesSpringBeanId" + it.metadataFilters.add(new EntityAttributesFilter().with { + it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { + it.entityAttributesFilterTargetType = ENTITY + it.setValue(["hola"]) + return it + } + return it + }) + return it + } + repositoryUnderTest.save(mdr) + + then: + repositoryUnderTest.findAll().size() > 0 + FileBackedHttpMetadataResolver item = repositoryUnderTest.findByName("FileBackedHttpMetadata") + + item.name == "FileBackedHttpMetadata" + item.metadataFilters.size() == 1 + item.metadataFilters[0].entityAttributesFilterTarget.entityAttributesFilterTargetType == ENTITY + item.metadataFilters[0].entityAttributesFilterTarget.value.size() == 1 + item.metadataFilters[0].entityAttributesFilterTarget.value.get(0) == "hola" + item.httpMetadataResolverAttributes.connectionRequestTimeout == "PT05" + item.httpMetadataResolverAttributes.disregardTLSCertificate + item.httpMetadataResolverAttributes.httpCaching == memory + item.reloadableMetadataResolverAttributes.indexesRef == "indexesSpringBeanId" + } +} From a4eaecc4c940fef65cbbb311943e24f4e943f7ec Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Fri, 18 May 2018 15:37:57 -0400 Subject: [PATCH 3/7] Tests polishing --- ...HttpMetadataResolverRepositoryTests.groovy | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) 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 710a966d3..0cef56367 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 @@ -31,22 +31,27 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { when: def mdr = new FileBackedHttpMetadataResolver().with { it.name = "FileBackedHttpMetadata" - it.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes() - it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes() - it.httpMetadataResolverAttributes.connectionRequestTimeout = "PT05" - it.httpMetadataResolverAttributes.disregardTLSCertificate = true - it.httpMetadataResolverAttributes.httpCaching = memory - it.reloadableMetadataResolverAttributes.indexesRef = "indexesSpringBeanId" + it.httpMetadataResolverAttributes = new HttpMetadataResolverAttributes().with { + it.connectionRequestTimeout = "PT05" + it.disregardTLSCertificate = true + it.httpCaching = memory + it + } + it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes().with { + it.indexesRef = "indexesSpringBeanId" + it + } + it.metadataFilters.add(new EntityAttributesFilter().with { it.entityAttributesFilterTarget = new EntityAttributesFilterTarget().with { it.entityAttributesFilterTargetType = ENTITY it.setValue(["hola"]) - return it + it } - return it + it }) - return it + it } repositoryUnderTest.save(mdr) From 65b42b3ee0e335a2bfba84c42fa5ab4a8ed813e5 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Mon, 21 May 2018 16:06:35 -0700 Subject: [PATCH 4/7] [SHIBUI-517] First pass at FileBackedHttpMetadataProviderController. More to come. --- ...eBackedHttpMetadataProviderController.java | 82 +++++++++++++++++++ .../ui/domain/resolvers/MetadataResolver.java | 3 + ...eBackedHttpMetadataResolverRepository.java | 2 + 3 files changed, 87 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java new file mode 100644 index 000000000..56fa92729 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java @@ -0,0 +1,82 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.repository.FileBackedHttpMetadataResolverRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.DeleteMapping; +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; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.net.URI; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@RestController +@RequestMapping("/api/MetadataProvider/FileBackedHttp") +public class FileBackedHttpMetadataProviderController { + + @Autowired + FileBackedHttpMetadataResolverRepository repository; + + @DeleteMapping("/{resourceId}") + public ResponseEntity deleteByResourceId(@PathVariable String resourceId) { + if (repository.deleteByResourceId(resourceId)) { + return ResponseEntity.accepted().build(); + } else { + return ResponseEntity.notFound().build(); + } + } + + @GetMapping("/name/{metadataProviderName}") + @Transactional(readOnly = true) + public ResponseEntity getOneByName(@PathVariable String metadataProviderName) { + return ResponseEntity.ok(repository.findByName(metadataProviderName)); + } + + @GetMapping("/{resourceId}") + @Transactional(readOnly = true) + public ResponseEntity getOneByResourceId(@PathVariable String resourceId) { + return ResponseEntity.ok(repository.findByResourceId(resourceId)); + } + + @PostMapping + public ResponseEntity create(@RequestBody FileBackedHttpMetadataResolver resolver) { + //TODO: Check for duplicates based on name + FileBackedHttpMetadataResolver persistedResolver = repository.save(resolver); + + return ResponseEntity + .created(getResourceUriFor(persistedResolver)) + .body(persistedResolver); + + } + + @PutMapping + public ResponseEntity update(@RequestBody FileBackedHttpMetadataResolver resolver) { + FileBackedHttpMetadataResolver existingResolver = repository.findByResourceId(resolver.getResourceId()); + //TODO: Handle not found. + //TODO: Handle contention. + + resolver.setAudId(existingResolver.getAudId()); + + FileBackedHttpMetadataResolver updatedResolver = repository.save(resolver); + + return ResponseEntity.ok(updatedResolver); + } + + private static URI getResourceUriFor(FileBackedHttpMetadataResolver resolver) { + return ServletUriComponentsBuilder + .fromCurrentServletMapping().path("/api/MetadataProvider/FileBackedHttp/") + .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 e211cb27d..f8ad0c216 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 @@ -9,6 +9,7 @@ import lombok.ToString; import javax.persistence.CascadeType; +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; @@ -27,8 +28,10 @@ @ToString public class MetadataResolver extends AbstractAuditable { + @Column(unique=true) private String name; + @Column(unique=true) private String resourceId = UUID.randomUUID().toString(); private Boolean requireValidMetadata; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java index c4adea391..97d069173 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/repository/FileBackedHttpMetadataResolverRepository.java @@ -9,4 +9,6 @@ public interface FileBackedHttpMetadataResolverRepository extends CrudRepository { FileBackedHttpMetadataResolver findByName(String name); + boolean deleteByResourceId(String resourceId); + FileBackedHttpMetadataResolver findByResourceId(String resourceId); } From ea3b0e9c61d0304bb17817c6c9d169264d3224fa Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Thu, 24 May 2018 12:45:29 -0700 Subject: [PATCH 5/7] [SHIBUI-517] Updates to controller and tests. More tests incoming. --- ...eBackedHttpMetadataProviderController.java | 39 +++++++++++-- .../admin/ui/domain/AbstractAuditable.java | 2 + .../HttpMetadataResolverAttributes.java | 2 + .../ui/domain/resolvers/MetadataResolver.java | 8 ++- .../ReloadableMetadataResolverAttributes.java | 2 + ...HttpMetadataResolverRepositoryTests.groovy | 57 ++++++++++++++++++- 6 files changed, 102 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java index 56fa92729..572c728ae 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java @@ -2,7 +2,10 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.repository.FileBackedHttpMetadataResolverRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; 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.DeleteMapping; @@ -23,6 +26,7 @@ @RestController @RequestMapping("/api/MetadataProvider/FileBackedHttp") public class FileBackedHttpMetadataProviderController { + private static final Logger logger = LoggerFactory.getLogger(FileBackedHttpMetadataProviderController.class); @Autowired FileBackedHttpMetadataResolverRepository repository; @@ -39,33 +43,56 @@ public ResponseEntity deleteByResourceId(@PathVariable String resourceId) { @GetMapping("/name/{metadataProviderName}") @Transactional(readOnly = true) public ResponseEntity getOneByName(@PathVariable String metadataProviderName) { - return ResponseEntity.ok(repository.findByName(metadataProviderName)); + FileBackedHttpMetadataResolver resolver = repository.findByResourceId(metadataProviderName); + if (resolver == null) { + return ResponseEntity.notFound().build(); + } else { + resolver.setVersion(resolver.hashCode()); + return ResponseEntity.ok(resolver); + } } @GetMapping("/{resourceId}") @Transactional(readOnly = true) public ResponseEntity getOneByResourceId(@PathVariable String resourceId) { - return ResponseEntity.ok(repository.findByResourceId(resourceId)); + FileBackedHttpMetadataResolver resolver = repository.findByResourceId(resourceId); + if (resolver == null) { + return ResponseEntity.notFound().build(); + } else { + resolver.setVersion(resolver.hashCode()); + return ResponseEntity.ok(resolver); + } } @PostMapping public ResponseEntity create(@RequestBody FileBackedHttpMetadataResolver resolver) { - //TODO: Check for duplicates based on name + if (repository.findByName(resolver.getName()) != null) { + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + FileBackedHttpMetadataResolver persistedResolver = repository.save(resolver); + persistedResolver.setVersion(persistedResolver.hashCode()); return ResponseEntity .created(getResourceUriFor(persistedResolver)) .body(persistedResolver); - } @PutMapping public ResponseEntity update(@RequestBody FileBackedHttpMetadataResolver resolver) { FileBackedHttpMetadataResolver existingResolver = repository.findByResourceId(resolver.getResourceId()); - //TODO: Handle not found. - //TODO: Handle contention. + + if (existingResolver == null) { + return ResponseEntity.notFound().build(); + } + + if (existingResolver.hashCode() != resolver.getVersion()) { + logger.info("Comparing: " + existingResolver.hashCode() + " with " + resolver.getVersion()); + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } resolver.setAudId(existingResolver.getAudId()); + //TODO: Do we need to set anything else? dates? FileBackedHttpMetadataResolver updatedResolver = repository.save(resolver); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java index 8f530bdd6..1d23d5113 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/AbstractAuditable.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain; +import lombok.EqualsAndHashCode; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import org.springframework.data.annotation.CreatedBy; @@ -20,6 +21,7 @@ @MappedSuperclass @EntityListeners(AuditingEntityListener.class) +@EqualsAndHashCode public abstract class AbstractAuditable implements Auditable { @Id diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java index cc880cc32..437516ffd 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/HttpMetadataResolverAttributes.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -16,6 +17,7 @@ @AllArgsConstructor @Getter @Setter +@EqualsAndHashCode public class HttpMetadataResolverAttributes { private String httpClientRef; 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 f8ad0c216..4deebcbcb 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 @@ -15,13 +15,15 @@ import javax.persistence.InheritanceType; import javax.persistence.OneToMany; +import javax.persistence.OrderColumn; +import javax.persistence.Transient; import java.util.ArrayList; import java.util.List; import java.util.UUID; @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = true, exclude={"version"}) @NoArgsConstructor @Getter @Setter @@ -47,5 +49,9 @@ public class MetadataResolver extends AbstractAuditable { private Boolean satisfyAnyPredicates; @OneToMany(cascade = CascadeType.ALL) + @OrderColumn private List metadataFilters = new ArrayList<>(); + + @Transient + private int version; } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java index ad21f7a23..cddf5b935 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/ReloadableMetadataResolverAttributes.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -12,6 +13,7 @@ @AllArgsConstructor @Getter @Setter +@EqualsAndHashCode public class ReloadableMetadataResolverAttributes { private String parserPoolRef; 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 0cef56367..d4aea60ba 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 @@ -1,5 +1,6 @@ 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 @@ -12,21 +13,28 @@ 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 static edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget.EntityAttributesFilterTargetType.* +import javax.persistence.EntityManager + +import static edu.internet2.tier.shibboleth.admin.ui.domain.EntityAttributesFilterTarget.EntityAttributesFilterTargetType.ENTITY import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes.HttpCachingType.memory @DataJpaTest @ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") +@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) class FileBackedHttpMetadataResolverRepositoryTests extends Specification { @Autowired FileBackedHttpMetadataResolverRepository repositoryUnderTest + @Autowired + EntityManager entityManager + def "file backed http metadata resolver instances persist OK"() { when: def mdr = new FileBackedHttpMetadataResolver().with { @@ -69,4 +77,51 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { item.httpMetadataResolverAttributes.httpCaching == memory item.reloadableMetadataResolverAttributes.indexesRef == "indexesSpringBeanId" } + + def "FileBackedHttpMetadataResolver hashcode works as desired"() { + given: + // TODO: Ask JJ why an empty reloadableMetadataResolverAttributes object results in a null object for item2 below + def resolverJson = '''{ + "name": "name", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}''' + + when: + def resolver = new ObjectMapper().readValue(resolverJson.bytes, FileBackedHttpMetadataResolver) + def persistedResolver = repositoryUnderTest.save(resolver) + entityManager.flush() + + then: + entityManager.clear() + def item1 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId) + entityManager.clear() + def item2 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId) + + item1.hashCode() == item2.hashCode() + } } From fb9eb6a6564a572d8222660c77f83188ae31ea4e Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Fri, 25 May 2018 11:53:46 -0700 Subject: [PATCH 6/7] [SHIBUI-517] Added unit tests for all controller operations. --- ...eBackedHttpMetadataProviderController.java | 3 +- ...HttpMetadataProviderControllerTests.groovy | 594 ++++++++++++++++++ ...HttpMetadataResolverRepositoryTests.groovy | 5 +- 3 files changed, 599 insertions(+), 3 deletions(-) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java index 572c728ae..5b8000482 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderController.java @@ -43,7 +43,7 @@ public ResponseEntity deleteByResourceId(@PathVariable String resourceId) { @GetMapping("/name/{metadataProviderName}") @Transactional(readOnly = true) public ResponseEntity getOneByName(@PathVariable String metadataProviderName) { - FileBackedHttpMetadataResolver resolver = repository.findByResourceId(metadataProviderName); + FileBackedHttpMetadataResolver resolver = repository.findByName(metadataProviderName); if (resolver == null) { return ResponseEntity.notFound().build(); } else { @@ -95,6 +95,7 @@ public ResponseEntity update(@RequestBody FileBackedHttpMetadataResolver reso //TODO: Do we need to set anything else? dates? FileBackedHttpMetadataResolver updatedResolver = repository.save(resolver); + updatedResolver.setVersion(updatedResolver.hashCode()); return ResponseEntity.ok(updatedResolver); } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy new file mode 100644 index 000000000..377722b5d --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy @@ -0,0 +1,594 @@ +package edu.internet2.tier.shibboleth.admin.ui.controller + +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.domain.resolvers.FileBackedHttpMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.repository.FileBackedHttpMetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator +import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +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.context.ContextConfiguration +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import spock.lang.Specification + +import static org.hamcrest.CoreMatchers.containsString +import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8 +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.* +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.* + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@DataJpaTest +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, MetadataResolverConfiguration]) +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +class FileBackedHttpMetadataProviderControllerTests extends Specification { + TestObjectGenerator testObjectGenerator + RandomGenerator randomGenerator + ObjectMapper mapper + + def repository = Mock(FileBackedHttpMetadataResolverRepository) + def controller + def mockMvc + + def setup() { + randomGenerator = new RandomGenerator() + //testObjectGenerator = new TestObjectGenerator(attributeUtility) + mapper = new ObjectMapper() + + controller = new FileBackedHttpMetadataProviderController ( + repository: repository + ) + + mockMvc = MockMvcBuilders.standaloneSetup(controller).build() + } + + def "DELETE deletes the desired resolver"() { + given: + def randomResourceId = randomGenerator.randomId() + + 1 * repository.deleteByResourceId(randomResourceId) >> true + + when: + def result = mockMvc.perform( + delete("/api/MetadataProvider/FileBackedHttp/$randomResourceId")) + + then: + result.andExpect(status().isAccepted()) + } + + def "DELETE returns error when desired resolver is not found"() { + given: + def randomResourceId = randomGenerator.randomId() + + 1 * repository.deleteByResourceId(randomResourceId) >> false + + when: + def result = mockMvc.perform( + delete("/api/MetadataProvider/FileBackedHttp/$randomResourceId")) + + then: + result.andExpect(status().isNotFound()) + } + + def "POST a new resolver properly persists and returns the new persisted resolver"() { + given: + def postedJsonBody = '''{ + "name": "name", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}''' + def resolver = new ObjectMapper().readValue(postedJsonBody.bytes, FileBackedHttpMetadataResolver) + 1 * repository.findByName(resolver.getName()) >> null + 1 * repository.save(_) >> resolver + + def expectedResolverUUID = resolver.getResourceId() + def expectedResponseHeader = 'Location' + def expectedResponseHeaderValue = "/api/MetadataProvider/FileBackedHttp/$expectedResolverUUID" + + when: + def result = mockMvc.perform( + post('/api/MetadataProvider/FileBackedHttp') + .contentType(APPLICATION_JSON_UTF8) + .content(postedJsonBody)) + + then: + result.andExpect(status().isCreated()) + .andExpect(content().json(postedJsonBody, false)) + .andExpect(header().string(expectedResponseHeader, containsString(expectedResponseHeaderValue))) + + } + + def "POST a new resolver that has a name of a persisted resolver returns conflict"() { + given: + def randomResolverName = randomGenerator.randomString(10) + def postedJsonBody = """{ + "name": "$randomResolverName", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + def resolver = new ObjectMapper().readValue(postedJsonBody.bytes, FileBackedHttpMetadataResolver) + 1 * repository.findByName(randomResolverName) >> resolver + 0 * repository.save(_) + + when: + def result = mockMvc.perform( + post('/api/MetadataProvider/FileBackedHttp') + .contentType(APPLICATION_JSON_UTF8) + .content(postedJsonBody)) + + then: + result.andExpect(status().isConflict()) + } + + def "GET by resourceId returns the desired persisted resolver"() { + given: + def randomUUID = randomGenerator.randomId() + def resolverJson = """{ + "name": "name", + "resourceId": "$randomUUID", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + + def resolver = new ObjectMapper().readValue(resolverJson.bytes, FileBackedHttpMetadataResolver) + resolver.setResourceId(randomUUID) + + 1 * repository.findByResourceId(randomUUID) >> resolver + + def expectedResponseContentType = APPLICATION_JSON_UTF8 + + when: + def result = mockMvc.perform( + get("/api/MetadataProvider/FileBackedHttp/$randomUUID")) + + then: + result.andExpect(status().isOk()) + .andExpect(content().contentType(expectedResponseContentType)) + .andExpect(content().json(resolverJson, false)) + } + + def "GET by unknown resource id returns not found"() { + given: + def randomResourceId = randomGenerator.randomId() + + 1 * repository.findByResourceId(randomResourceId) >> null + + when: + def result = mockMvc.perform( + get("/api/MetadataProvider/FileBackedHttp/$randomResourceId")) + + then: + result.andExpect(status().isNotFound()) + } + + def "GET by resolver name returns the desired persisted resolver"() { + given: + def randomResolverName = randomGenerator.randomString(10) + def resolverJson = """{ + "name": "$randomResolverName", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + + def resolver = new ObjectMapper().readValue(resolverJson.bytes, FileBackedHttpMetadataResolver) + + 1 * repository.findByName(randomResolverName) >> resolver + + def expectedResponseContentType = APPLICATION_JSON_UTF8 + + when: + def result = mockMvc.perform( + get("/api/MetadataProvider/FileBackedHttp/name/$randomResolverName")) + + then: + result.andExpect(status().isOk()) + .andExpect(content().contentType(expectedResponseContentType)) + .andExpect(content().json(resolverJson, false)) + } + + def "GET by unknown resolver name returns not found"() { + given: + def randomResolverName = randomGenerator.randomString(10) + + 1 * repository.findByName(randomResolverName) >> null + + when: + def result = mockMvc.perform( + get("/api/MetadataProvider/FileBackedHttp/name/$randomResolverName")) + + then: + result.andExpect(status().isNotFound()) + } + + def "PUT allows for a successful update of an already-persisted resolver"() { + given: + def randomResourceId = "resourceId" + def existingResolverJson = """{ + "name": "name", + "resourceId": "$randomResourceId", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + def existingResolver = new ObjectMapper().readValue(existingResolverJson.bytes, FileBackedHttpMetadataResolver) + def existingResolverVersion = existingResolver.hashCode() + + def randomName = randomGenerator.randomString(10) + def postedJsonBody = """{ + "name": "$randomName", + "resourceId": "$randomResourceId", + "version": "$existingResolverVersion", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + def updatedResolver = new ObjectMapper().readValue(postedJsonBody.bytes, FileBackedHttpMetadataResolver) + 1 * repository.findByResourceId(randomResourceId) >> existingResolver + 1 * repository.save(_) >> updatedResolver + + def expectedResponseContentType = APPLICATION_JSON_UTF8 + + when: + def result = mockMvc.perform( + put('/api/MetadataProvider/FileBackedHttp') + .contentType(APPLICATION_JSON_UTF8) + .content(postedJsonBody)) + + then: + def expectedJson = new JsonSlurper().parseText(postedJsonBody) + expectedJson << [version: updatedResolver.hashCode()] + result.andExpect(status().isOk()) + .andExpect(content().contentType(expectedResponseContentType)) + .andExpect(content().json(JsonOutput.toJson(expectedJson), false)) + } + + def "PUT of an updated resolver with an incorrect version returns a conflict"() { + given: + def randomResourceId = "resourceId" + def existingResolverJson = """{ + "name": "name", + "resourceId": "$randomResourceId", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + def existingResolver = new ObjectMapper().readValue(existingResolverJson.bytes, FileBackedHttpMetadataResolver) + def existingResolverVersion = existingResolver.hashCode() + + def randomName = randomGenerator.randomString(10) + def randomVersion = randomGenerator.randomInt() + def postedJsonBody = """{ + "name": "$randomName", + "resourceId": "$randomResourceId", + "version": "$randomVersion", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + 1 * repository.findByResourceId(randomResourceId) >> existingResolver + 0 * repository.save(_) + + when: + def result = mockMvc.perform( + put('/api/MetadataProvider/FileBackedHttp') + .contentType(APPLICATION_JSON_UTF8) + .content(postedJsonBody)) + + then: + result.andExpect(status().isConflict()) + } + + def "PUT of a resolver that is not persisted returns not found"() { + given: + def randomResourceId = randomGenerator.randomId() + def postedJsonBody = """{ + "name": "name", + "resourceId": "$randomResourceId", + "requireValidMetadata": true, + "failFastInitialization": true, + "sortKey": 7, + "criterionPredicateRegistryRef": "criterionPredicateRegistryRef", + "useDefaultPredicateRegistry": true, + "satisfyAnyPredicates": true, + "metadataFilters": [], + "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef", + "taskTimerRef": "taskTimerRef", + "minRefreshDelay": "minRefreshDelay", + "maxRefreshDelay": "maxRefreshDelay", + "refreshDelayFactor": 1.0, + "indexesRef": "indexesRef", + "resolveViaPredicatesOnly": true, + "expirationWarningThreshold": "expirationWarningThreshold" + }, + "httpMetadataResolverAttributes": { + "httpClientRef": "httpClientRef", + "connectionRequestTimeout": "connectionRequestTimeout", + "requestTimeout": "requestTimeout", + "socketTimeout": "socketTimeout", + "disregardTLSCertificate": true, + "tlsTrustEngineRef": "tlsTrustEngineRef", + "httpClientSecurityParametersRef": "httpClientSecurityParametersRef", + "proxyHost": "proxyHost", + "proxyPort": "proxyPort", + "proxyUser": "proxyUser", + "proxyPassword": "proxyPassword", + "httpCaching": "none", + "httpCacheDirectory": "httpCacheDirectory", + "httpMaxCacheEntries": 1, + "httpMaxCacheEntrySize": 2 + } +}""" + 1 * repository.findByResourceId(randomResourceId) >> null + 0 * repository.save(_) + + when: + def result = mockMvc.perform( + put('/api/MetadataProvider/FileBackedHttp') + .contentType(APPLICATION_JSON_UTF8) + .content(postedJsonBody)) + + then: + result.andExpect(status().isNotFound()) + } +} 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 d4aea60ba..d0beb24d2 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 @@ -80,7 +80,8 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { def "FileBackedHttpMetadataResolver hashcode works as desired"() { given: - // TODO: Ask JJ why an empty reloadableMetadataResolverAttributes object results in a null object for item2 below + // TODO: There is weirdness here if reloadableMetadataResolverAttributes is empty. + // I suspect similar weirdness if httpMetadataResolverAttributes is an empty object, too. def resolverJson = '''{ "name": "name", "requireValidMetadata": true, @@ -91,6 +92,7 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { "satisfyAnyPredicates": true, "metadataFilters": [], "reloadableMetadataResolverAttributes": { + "parserPoolRef": "parserPoolRef" }, "httpMetadataResolverAttributes": { "httpClientRef": "httpClientRef", @@ -117,7 +119,6 @@ class FileBackedHttpMetadataResolverRepositoryTests extends Specification { entityManager.flush() then: - entityManager.clear() def item1 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId) entityManager.clear() def item2 = repositoryUnderTest.findByResourceId(persistedResolver.resourceId) From 7d0c33ce669a0ba08294002e3c0ec2d3fa9df02f Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Fri, 25 May 2018 12:00:57 -0700 Subject: [PATCH 7/7] [SHIBUI-517] Small refactor. --- .../FileBackedHttpMetadataProviderControllerTests.groovy | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy index 377722b5d..1cf30ab69 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/FileBackedHttpMetadataProviderControllerTests.groovy @@ -7,7 +7,6 @@ import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver import edu.internet2.tier.shibboleth.admin.ui.repository.FileBackedHttpMetadataResolverRepository import edu.internet2.tier.shibboleth.admin.ui.util.RandomGenerator -import edu.internet2.tier.shibboleth.admin.ui.util.TestObjectGenerator import groovy.json.JsonOutput import groovy.json.JsonSlurper import org.springframework.boot.autoconfigure.domain.EntityScan @@ -30,7 +29,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") class FileBackedHttpMetadataProviderControllerTests extends Specification { - TestObjectGenerator testObjectGenerator RandomGenerator randomGenerator ObjectMapper mapper @@ -40,7 +38,6 @@ class FileBackedHttpMetadataProviderControllerTests extends Specification { def setup() { randomGenerator = new RandomGenerator() - //testObjectGenerator = new TestObjectGenerator(attributeUtility) mapper = new ObjectMapper() controller = new FileBackedHttpMetadataProviderController (