From 551cec5ca62f6e0773d6f413d4814e89bda7f8bd Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 26 Jun 2018 12:08:01 -0400 Subject: [PATCH] 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