From 015986276baa60a7a78ac22b148a051430075444 Mon Sep 17 00:00:00 2001 From: chasegawa Date: Tue, 17 Aug 2021 16:31:42 -0700 Subject: [PATCH] SHIBUI-2024 Added validation for DynamicHttpMetadataResolver url --- ...tadataResolverValidationConfiguration.java | 10 +- .../DynamicHttpMetadataResolverValidator.java | 31 +++++ ...dataResolverValidationConfiguration.groovy | 7 + ...cHttpMetadataResolverValidatorTests.groovy | 123 ++++++++++++++++++ 4 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidator.java create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidatorTests.groovy 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 b5609f60d..12c076c42 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 @@ -1,10 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; -import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.DurationIMetadataResolverValidator; -import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.MetadataResolverValidationService; -import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.FileBackedHttpMetadataResolverValidator; -import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.IMetadataResolverValidator; -import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.ResourceBackedIMetadataResolverValidator; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.*; import edu.internet2.tier.shibboleth.admin.ui.security.service.IGroupService; import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService; import org.springframework.context.annotation.Bean; @@ -19,6 +15,10 @@ public class MetadataResolverValidationConfiguration { return new ResourceBackedIMetadataResolverValidator(); } + @Bean DynamicHttpMetadataResolverValidator dynamicHttpMetadataResolverValidator(IGroupService groupService, UserService userService) { + return new DynamicHttpMetadataResolverValidator(groupService, userService); + } + @Bean FileBackedHttpMetadataResolverValidator fileBackedHttpMetadataResolverValidator(IGroupService groupService, UserService userService) { return new FileBackedHttpMetadataResolverValidator(groupService, userService); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidator.java new file mode 100644 index 000000000..a161ec2fa --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidator.java @@ -0,0 +1,31 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator; + +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; +import edu.internet2.tier.shibboleth.admin.ui.security.service.IGroupService; +import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; + +public class DynamicHttpMetadataResolverValidator implements IMetadataResolverValidator { + @Autowired IGroupService groupService; + + @Autowired UserService userService; + + public DynamicHttpMetadataResolverValidator(IGroupService groupService, UserService userService) { + this.groupService = groupService; + this.userService = userService; + } + + @Override public boolean supports(MetadataResolver resolver) { return resolver instanceof DynamicHttpMetadataResolver; } + + @Override public ValidationResult validate(MetadataResolver resolver) { + DynamicHttpMetadataResolver dynamicResolver = (DynamicHttpMetadataResolver) resolver; + if ("MetadataQueryProtocol".equals(dynamicResolver.getMetadataRequestURLConstructionScheme().getType())) { + String url = dynamicResolver.getMetadataRequestURLConstructionScheme().getContent(); + if (!groupService.doesUrlMatchGroupPattern(userService.getCurrentUser().getGroupId(), url)) { + return new ValidationResult("Metadata Query Protocol URL not acceptable for user's group"); + } + } + return new ValidationResult(); + } +} \ No newline at end of file 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 37f69ff8c..6daa2c816 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 @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.DynamicHttpMetadataResolverValidator import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.MetadataResolverValidationService import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.FileBackedHttpMetadataResolverValidator import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator.IMetadataResolverValidator @@ -15,6 +16,12 @@ import org.springframework.context.annotation.Profile @Configuration class TestMetadataResolverValidationConfiguration { + @Bean + @Profile("dh-test") + DynamicHttpMetadataResolverValidator dynamicHttpMetadataResolverValidator(IGroupService groupService, UserService userService) { + new DynamicHttpMetadataResolverValidator(groupService, userService) + } + @Bean @Profile("fbh-test") FileBackedHttpMetadataResolverValidator fileBackedHttpMetadataResolverValidator(IGroupService groupService, UserService userService) { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidatorTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidatorTests.groovy new file mode 100644 index 000000000..7b4470b18 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/validator/DynamicHttpMetadataResolverValidatorTests.groovy @@ -0,0 +1,123 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.validator + +import edu.internet2.tier.shibboleth.admin.ui.configuration.* +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicHttpMetadataResolver +import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataQueryProtocolScheme +import edu.internet2.tier.shibboleth.admin.ui.security.model.Group +import edu.internet2.tier.shibboleth.admin.ui.security.model.Role +import edu.internet2.tier.shibboleth.admin.ui.security.model.User +import edu.internet2.tier.shibboleth.admin.ui.security.repository.GroupsRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.OwnershipRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository +import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository +import edu.internet2.tier.shibboleth.admin.ui.security.service.GroupServiceForTesting +import edu.internet2.tier.shibboleth.admin.ui.security.service.GroupServiceImpl +import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Primary +import org.springframework.context.annotation.Profile +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.annotation.Rollback +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.ContextConfiguration +import org.springframework.transaction.annotation.Transactional +import spock.lang.Specification + +@DataJpaTest +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration, InternationalizationConfiguration, TestMetadataResolverValidationConfiguration, LocalConfig]) +@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) +@EntityScan("edu.internet2.tier.shibboleth.admin.ui") +@ActiveProfiles(["dh-test"]) +class DynamicHttpMetadataResolverValidatorTests extends Specification { + @Autowired + GroupServiceForTesting groupServiceForTesting + + @Autowired + @Qualifier("metadataResolverValidationService") + MetadataResolverValidationService metadataResolverValidationService + + @Autowired + RoleRepository roleRepository + + @Autowired + UserRepository userRepository + + @Autowired + UserService userService + + @Transactional + def setup() { + userRepository.deleteAll() + roleRepository.deleteAll() + groupServiceForTesting.clearAllForTesting() + + Group g = new Group() + g.setResourceId("shib") + g.setName("shib") + // This is valid for a url with "shib.org" in it + g.setValidationRegex("^(?:https?:\\/\\/)?(?:[^.]+\\.)?shib\\.org(\\/.*)?\$") + g = groupServiceForTesting.createGroup(g) + + def roles = [new Role().with { + name = 'ROLE_ADMIN' + it + }, new Role().with { + name = 'ROLE_USER' + it + }, new Role().with { + name = 'ROLE_NONE' + it + }] + roles.each { + roleRepository.save(it) + } + + Optional userRole = roleRepository.findByName("ROLE_USER") + User user = new User(username: "someUser", roles:[userRole.get()], password: "foo", group: g) + userService.save(user) + } + + @WithMockUser(value = "someUser", roles = ["USER"]) + @Rollback + def "test validation by service works properly"() { + given: + DynamicHttpMetadataResolver metadataResolver = new DynamicHttpMetadataResolver() + MetadataQueryProtocolScheme scheme = new MetadataQueryProtocolScheme() + scheme.setContent("http://foo.shib.org/bar") + metadataResolver.setMetadataRequestURLConstructionScheme(scheme) + + when: + IMetadataResolverValidator.ValidationResult result = metadataResolverValidationService.validateIfNecessary(metadataResolver) + + then: + result.isValid() + + when: "using a bad url (no match)" + metadataResolver.getMetadataRequestURLConstructionScheme().setContent("http://foo.shib.com/bar") + result = metadataResolverValidationService.validateIfNecessary(metadataResolver) + + then: + !result.isValid() + } + + @org.springframework.boot.test.context.TestConfiguration + @Profile("dh-test") + static class LocalConfig { + @Bean + @Primary + GroupServiceForTesting groupServiceForTesting(GroupsRepository repo, OwnershipRepository ownershipRepository) { + GroupServiceForTesting result = new GroupServiceForTesting(new GroupServiceImpl().with { + it.groupRepository = repo + it.ownershipRepository = ownershipRepository + return it + }) + result.ensureAdminGroupExists() + return result + } + } +} \ No newline at end of file