From 0cd425443fa51158ac2d11dd4da6be12fd5c5676 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 08:13:29 -0400 Subject: [PATCH 01/25] SHIBUI-836: work in progress --- .../admin/ui/ShibbolethUiApplication.java | 6 ++ ...eValueSettingEnvironmentPostProcessor.java | 57 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 + 3 files changed, 65 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java create mode 100644 backend/src/main/resources/META-INF/spring.factories diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java index 1fc74cf9d..2c241cf8e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java @@ -2,6 +2,7 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -36,10 +37,15 @@ public static class MetadataResolversResourceIdEmitter { @Autowired MetadataResolverRepository metadataResolverRepository; + @Value("${idp.home}") + String idpHome; + @EventListener void showMetadataResolversResourceIds(ApplicationStartedEvent e) { metadataResolverRepository.findAll() .forEach(it -> System.out.println(String.format("MetadataResolver [%s: %s]", it.getName(), it.getResourceId()))); + + System.out.println("IDP HOME: " + idpHome); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java new file mode 100644 index 000000000..74b35f362 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java @@ -0,0 +1,57 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration.postprocessors; + +import lombok.extern.log4j.Log4j2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +/** + * Spring Boot Environment Post Processor setting the value for idp.home property to an abstract temp directory. + * + * @author Dmitriy Kopylenko + */ +public class IdpHomeValueSettingEnvironmentPostProcessor implements EnvironmentPostProcessor { + + private static final String IDP_HOME_PROP = "idp.home"; + + private static final String METADATA_DIR = "metadata"; + + private static final Logger LOGGER = LoggerFactory.getLogger(IdpHomeValueSettingEnvironmentPostProcessor.class); + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + String existingIdpHome = environment.getProperty(IDP_HOME_PROP); + Path metadataSubDir = Paths.get(existingIdpHome, METADATA_DIR); + if (existingIdpHome != null) { + if (!Files.exists(metadataSubDir)) { + try { + Files.createDirectories(metadataSubDir); + } catch (IOException e) { + LOGGER.error(e.getMessage()); + throw new RuntimeException(e); + } + } + return; + } + + Map map = new HashMap<>(1); + try { + map.put(IDP_HOME_PROP, Files.createTempDirectory(null).toAbsolutePath().toString()); + } catch (IOException e) { + LOGGER.error(e.getMessage()); + throw new RuntimeException(e); + } + environment.getPropertySources().addLast(new MapPropertySource("idp.home.propertysource", map)); + } +} diff --git a/backend/src/main/resources/META-INF/spring.factories b/backend/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..fc0a891d0 --- /dev/null +++ b/backend/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + edu.internet2.tier.shibboleth.admin.ui.configuration.postprocessors.IdpHomeValueSettingEnvironmentPostProcessor \ No newline at end of file From 7c8ef09b8882ac095d129e430f441976da1400d6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 10:20:31 -0400 Subject: [PATCH 02/25] SHIBUI-836: wip... property replacer API --- .../admin/ui/ShibbolethUiApplication.java | 12 ++++++++ ...eValueSettingEnvironmentPostProcessor.java | 9 ++++-- ...lverPropertyPlaceholderValuesReplacer.java | 17 +++++++++++ ...ertyPlaceholderValuesResolvingService.java | 29 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java index 2c241cf8e..db1779592 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java @@ -11,6 +11,8 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.context.annotation.Profile; import org.springframework.context.event.EventListener; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.env.PropertyResolver; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.stereotype.Component; @@ -40,12 +42,22 @@ public static class MetadataResolversResourceIdEmitter { @Value("${idp.home}") String idpHome; + @Autowired + PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer; + + @Autowired + PropertyResolver propertyResolver; + @EventListener void showMetadataResolversResourceIds(ApplicationStartedEvent e) { metadataResolverRepository.findAll() .forEach(it -> System.out.println(String.format("MetadataResolver [%s: %s]", it.getName(), it.getResourceId()))); System.out.println("IDP HOME: " + idpHome); + String rawValue = "%{idp.home}/metadata/file.xml"; + boolean hasToken = rawValue.contains("%{idp.home}"); + String resolvedIdpHome = propertyResolver.resolvePlaceholders("${idp.home}"); + String fullyResolvedDir = rawValue.replace("%{idp.home}", resolvedIdpHome); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java index 74b35f362..814a797c2 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java @@ -17,7 +17,8 @@ import java.util.Map; /** - * Spring Boot Environment Post Processor setting the value for idp.home property to an abstract temp directory. + * Spring Boot Environment Post Processor setting the value for idp.home property to an abstract temp directory + * if no IDP_HOME environment variable has been set already. * * @author Dmitriy Kopylenko */ @@ -47,7 +48,11 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp Map map = new HashMap<>(1); try { - map.put(IDP_HOME_PROP, Files.createTempDirectory(null).toAbsolutePath().toString()); + Path tempDir = Files.createTempDirectory(String.format("%s.%s.", "shibui", IDP_HOME_PROP)); + String tempDirName = tempDir.toAbsolutePath().toString(); + Path tempMetadataSubDir = Paths.get(tempDirName, METADATA_DIR); + Files.createDirectories(tempMetadataSubDir); + map.put(IDP_HOME_PROP, tempDirName); } catch (IOException e) { LOGGER.error(e.getMessage()); throw new RuntimeException(e); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java new file mode 100644 index 000000000..10887e97f --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java @@ -0,0 +1,17 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +/** + * An SPI to resolve and convert data for different types of {@link MetadataResolver}s from possible provided '%{}' placeholders + *

+ * Typical usage is - multiple replacers for concrete type of resolvers are configured in Spring Application Context, + * aggregated by {@link MetadataResolverPropertyPlaceholderValuesResolvingService} facade and then that facade is injected into upstream consumers of it + * such as REST controllers, etc. + * + * @author Dmitriy Kopylenko + */ +public interface MetadataResolverPropertyPlaceholderValuesReplacer { + + boolean supports(T metadataResolver); + + void replacePlaceholderValuesIfResolvableOrFail(T metadataResolver); +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java new file mode 100644 index 000000000..e7639cfde --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java @@ -0,0 +1,29 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; + +import java.util.ArrayList; +import java.util.List; + +/** + * A facade that aggregates {@link MetadataResolverPropertyPlaceholderValuesReplacer}s available to call just one of them supporting the type of a given resolver. + * If no {@link MetadataResolverPropertyPlaceholderValuesReplacer}s are configured, considers a noop. + * + * Uses chain-of-responsibility design pattern + * + * @author Dmitriy Kopylenko + */ +public class MetadataResolverPropertyPlaceholderValuesResolvingService { + + private List> replacers; + + public MetadataResolverPropertyPlaceholderValuesResolvingService(List> replacers) { + this.replacers = replacers != null ? replacers : new ArrayList<>(); + } + + public void replacePlacehoderValuesOrFail(T metadataResolver) { + this.replacers + .stream() + .filter(r -> r.supports(metadataResolver)) + .findFirst() + .ifPresent(r -> r.replacePlaceholderValuesIfResolvableOrFail(metadataResolver)); + } +} From 91c381092119f12c6883e2e6ae311b149e3c39d6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 11:42:17 -0400 Subject: [PATCH 03/25] SHIBUI-836 wip --- .../TokenPlaceholderValueResolvingService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java new file mode 100644 index 000000000..3193a51aa --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java @@ -0,0 +1,11 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +/** + * Generic API to resolve values from arbitrary tokenized placeholders such as '%{token.placeholder}' etc. + * + * @author Dmitriy Kopylenko + */ +public interface TokenPlaceholderValueResolvingService { + + String resolveValueFromTokenPlaceholder(String tokenPlaceholder); +} From f4a7b471f413d0975d2e96440abf2b4346f3f91f Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 11:50:15 -0400 Subject: [PATCH 04/25] SHIBUI-836 wip --- ...rtyPlaceholderBasedValueResolvingService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java new file mode 100644 index 000000000..ceb48f38a --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java @@ -0,0 +1,16 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +/** + * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's default property resolver + * which understands and replaces Shibboleth Idp specific placeholder prefix of '%{' with standard Spring's placeholder + * prefix of '${' before resolving. + * + * If passed it value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. + */ +public class SpringPropertyPlaceholderBasedValueResolvingService implements TokenPlaceholderValueResolvingService { + + @Override + public String resolveValueFromTokenPlaceholder(String tokenPlaceholder) { + return null; + } +} From 76a861f4341042bd4c31285cb7b1219c02295d4b Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 11:52:35 -0400 Subject: [PATCH 05/25] SHIBUI-836: Refactor --- ...> ShibbolethPlaceholderTokenAwareValueResolvingService.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/{SpringPropertyPlaceholderBasedValueResolvingService.java => ShibbolethPlaceholderTokenAwareValueResolvingService.java} (83%) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java similarity index 83% rename from backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java rename to backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index ceb48f38a..50e49a6e3 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/SpringPropertyPlaceholderBasedValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -7,7 +7,7 @@ * * If passed it value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. */ -public class SpringPropertyPlaceholderBasedValueResolvingService implements TokenPlaceholderValueResolvingService { +public class ShibbolethPlaceholderTokenAwareValueResolvingService implements TokenPlaceholderValueResolvingService { @Override public String resolveValueFromTokenPlaceholder(String tokenPlaceholder) { From 60f97b5389a203a13e09251df3eda3e8afc0fae6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 12:03:17 -0400 Subject: [PATCH 06/25] SHIBUI-836 wip --- .../admin/ui/ShibbolethUiApplication.java | 1 + ...laceholderResolverComponentsConfiguration.java | 15 +++++++++++++++ ...laceholderTokenAwareValueResolvingService.java | 10 ++++++++++ .../TokenPlaceholderValueResolvingService.java | 7 +++++++ 4 files changed, 33 insertions(+) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java index db1779592..6fea0aa99 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java new file mode 100644 index 000000000..08a0069d4 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java @@ -0,0 +1,15 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration; + +import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.PropertyResolver; + +@Configuration +public class PlaceholderResolverComponentsConfiguration { + + @Bean + public TokenPlaceholderValueResolvingService tokenPlaceholderValueResolvingService(PropertyResolver propertyResolver) { + return TokenPlaceholderValueResolvingService.shibbolethPlaceholderAware(propertyResolver); + } +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 50e49a6e3..8de170b49 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -1,14 +1,24 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.env.PropertyResolver; + /** * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's default property resolver * which understands and replaces Shibboleth Idp specific placeholder prefix of '%{' with standard Spring's placeholder * prefix of '${' before resolving. * * If passed it value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. + * + * @author Dmitriy Kopylenko */ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements TokenPlaceholderValueResolvingService { + private PropertyResolver propertyResolver; + + ShibbolethPlaceholderTokenAwareValueResolvingService(PropertyResolver propertyResolver) { + this.propertyResolver = propertyResolver; + } + @Override public String resolveValueFromTokenPlaceholder(String tokenPlaceholder) { return null; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java index 3193a51aa..0df2f0ca0 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java @@ -1,11 +1,18 @@ package edu.internet2.tier.shibboleth.admin.ui.service; +import org.springframework.core.env.PropertyResolver; + /** * Generic API to resolve values from arbitrary tokenized placeholders such as '%{token.placeholder}' etc. * * @author Dmitriy Kopylenko */ +@FunctionalInterface public interface TokenPlaceholderValueResolvingService { String resolveValueFromTokenPlaceholder(String tokenPlaceholder); + + static TokenPlaceholderValueResolvingService shibbolethPlaceholderAware(PropertyResolver propertyResolver) { + return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertyResolver); + } } From 4b84cdef8ea4be58a1896ba11fe20d3cb29b3b90 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 16:37:35 -0400 Subject: [PATCH 07/25] SHIBUI-836: wip --- .../admin/ui/ShibbolethUiApplication.java | 6 +++--- ...eholderResolverComponentsConfiguration.java | 6 ++++++ ...eholderTokenAwareValueResolvingService.java | 7 +++++++ .../admin/util/TokenPlaceholderResolvers.java | 18 ++++++++++++++++++ ...tadataResolverValidationServiceTests.groovy | 10 +++++----- 5 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java index 6fea0aa99..aa19896ef 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java @@ -2,6 +2,7 @@ import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; +import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; @@ -56,9 +57,8 @@ void showMetadataResolversResourceIds(ApplicationStartedEvent e) { System.out.println("IDP HOME: " + idpHome); String rawValue = "%{idp.home}/metadata/file.xml"; - boolean hasToken = rawValue.contains("%{idp.home}"); - String resolvedIdpHome = propertyResolver.resolvePlaceholders("${idp.home}"); - String fullyResolvedDir = rawValue.replace("%{idp.home}", resolvedIdpHome); + String resolved = propertyResolver.resolvePlaceholders(rawValue.replace("%{", "${")); + TokenPlaceholderValueResolvingService service = TokenPlaceholderResolvers.placeholderResolverService(); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java index 08a0069d4..484675e3d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; +import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.PropertyResolver; @@ -12,4 +13,9 @@ public class PlaceholderResolverComponentsConfiguration { public TokenPlaceholderValueResolvingService tokenPlaceholderValueResolvingService(PropertyResolver propertyResolver) { return TokenPlaceholderValueResolvingService.shibbolethPlaceholderAware(propertyResolver); } + + @Bean + public TokenPlaceholderResolvers tokenPlaceholderResolvers(TokenPlaceholderValueResolvingService service) { + return new TokenPlaceholderResolvers(service); + } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 8de170b49..b4c6fd42a 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -2,6 +2,10 @@ import org.springframework.core.env.PropertyResolver; +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's default property resolver * which understands and replaces Shibboleth Idp specific placeholder prefix of '%{' with standard Spring's placeholder @@ -21,6 +25,9 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok @Override public String resolveValueFromTokenPlaceholder(String tokenPlaceholder) { + requireNonNull(tokenPlaceholder, "tokenPlaceholder must not be null"); + tokenPlaceholder.replace("%{", "${"); + return null; } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java new file mode 100644 index 000000000..f65737be2 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java @@ -0,0 +1,18 @@ +package edu.internet2.tier.shibboleth.admin.util; + +import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +public class TokenPlaceholderResolvers { + + private static TokenPlaceholderValueResolvingService placeholderResolverService; + + public TokenPlaceholderResolvers(TokenPlaceholderValueResolvingService service) { + TokenPlaceholderResolvers.placeholderResolverService = service; + } + + public static TokenPlaceholderValueResolvingService placeholderResolverService() { + return placeholderResolverService; + } +} 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 index d62f07170..eb6486916 100644 --- 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 @@ -11,7 +11,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataRe 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' + given: 'Sample metadata resolver and validation placeholderResolverService with no validators' def resolver = Mock(MetadataResolver) @Subject def validationService = new MetadataResolverValidationService(null) @@ -24,7 +24,7 @@ class MetadataResolverValidationServiceTests extends Specification { } 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' + given: 'Sample metadata resolver and validation placeholderResolverService with one validator not supporting that type' def resolver = Mock(MetadataResolver) def validator = Mock(MetadataResolverValidator) validator.supports(_) >> false @@ -39,7 +39,7 @@ class MetadataResolverValidationServiceTests extends Specification { } 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' + given: 'Sample metadata resolver and validation placeholderResolverService with one validator supporting that type' def resolver = Mock(MetadataResolver) def validator = Mock(MetadataResolverValidator) validator.supports(_) >> true @@ -55,7 +55,7 @@ class MetadataResolverValidationServiceTests extends Specification { } 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' + given: 'Sample metadata resolver and validation placeholderResolverService with two validators supporting that type' def resolver = Mock(MetadataResolver) def validator1 = Mock(MetadataResolverValidator) validator1.supports(_) >> true @@ -74,7 +74,7 @@ class MetadataResolverValidationServiceTests extends Specification { } 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' + given: 'Sample metadata resolver and validation placeholderResolverService with two validators, with one supporting that type' def resolver = Mock(MetadataResolver) def validator1 = Mock(MetadataResolverValidator) validator1.supports(_) >> false From ad2533a24cbd5a039dbb90ecf7113fa41d0a4471 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 16:57:42 -0400 Subject: [PATCH 08/25] SHIBUI-836: wip --- .../OpenSamlFileBackedHTTPMetadataResolver.java | 11 +++++++++-- .../OpenSamlMetadataResolverConstructorHelper.java | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java index 5f4c10905..7327458eb 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver; +import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; import net.shibboleth.utilities.java.support.xml.ParserPool; @@ -13,6 +14,7 @@ import javax.annotation.Nullable; import static edu.internet2.tier.shibboleth.admin.util.DurationUtility.toMillis; +import static edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers.placeholderResolverService; /** * @author Bill Smith (wsmith@unicon.net) @@ -38,8 +40,12 @@ public OpenSamlFileBackedHTTPMetadataResolver(ParserPool parserPool, OpenSamlMetadataResolverConstructorHelper.updateOpenSamlMetadataResolverFromReloadableMetadataResolverAttributes( this, sourceResolver.getReloadableMetadataResolverAttributes(), parserPool); - this.setBackupFile(sourceResolver.getBackingFile()); - this.setBackupFileInitNextRefreshDelay(toMillis(sourceResolver.getBackupFileInitNextRefreshDelay())); + //TODO: complete resolving placeholders everywhere + //This might throw runtime exception if unable to resolve placeholders sent from higher layers + this.setBackupFile(placeholderResolverService().resolveValueFromTokenPlaceholder(sourceResolver.getBackingFile())); + this.setBackupFileInitNextRefreshDelay(toMillis(placeholderResolverService() + .resolveValueFromTokenPlaceholder(sourceResolver.getBackupFileInitNextRefreshDelay()))); + this.setInitializeFromBackupFile(sourceResolver.getInitializeFromBackupFile()); //TODO: Where does this get set in OpenSAML land? @@ -63,6 +69,7 @@ protected void processConditionalRetrievalHeaders(HttpResponse response) { protected void initMetadataResolver() throws ComponentInitializationException { super.initMetadataResolver(); + delegate.addIndexedDescriptorsFromBackingStore(this.getBackingStore(), this.sourceResolver.getResourceId(), indexWriter); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java index c5a6845e4..9d0383c11 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java @@ -3,12 +3,14 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicMetadataResolverAttributes; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ReloadableMetadataResolverAttributes; +import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import net.shibboleth.utilities.java.support.xml.ParserPool; import org.opensaml.saml.metadata.resolver.MetadataResolver; import org.opensaml.saml.metadata.resolver.impl.AbstractDynamicMetadataResolver; import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver; import static edu.internet2.tier.shibboleth.admin.util.DurationUtility.toMillis; +import static edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers.placeholderResolverService; /** * @author Bill Smith (wsmith@unicon.net) @@ -85,9 +87,12 @@ public static void updateOpenSamlMetadataResolverFromReloadableMetadataResolverA //TODO: This takes a ParserPool. We've got a ParserPoolRef in attributes.getParserPoolRef(). Should we use it for anything? reloadingMetadataResolver.setParserPool(parserPool); + //TODO: finish placeholder resolving if (attributes != null) { if (attributes.getExpirationWarningThreshold() != null) { - reloadingMetadataResolver.setExpirationWarningThreshold(toMillis(attributes.getExpirationWarningThreshold())); + reloadingMetadataResolver + .setExpirationWarningThreshold(toMillis(placeholderResolverService() + .resolveValueFromTokenPlaceholder(attributes.getExpirationWarningThreshold()))); } if (attributes.getMaxRefreshDelay() != null) { reloadingMetadataResolver.setMaxRefreshDelay(toMillis(attributes.getMaxRefreshDelay())); From 5ce50ffd532b3a17d1ad6ede13b7aba1152601df Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 11 Sep 2018 17:04:38 -0400 Subject: [PATCH 09/25] SHIBUI-836: polishing --- .../MetadataResolverValidationServiceTests.groovy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 index eb6486916..d62f07170 100644 --- 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 @@ -11,7 +11,7 @@ import static edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataRe class MetadataResolverValidationServiceTests extends Specification { def "Validation service with no available validators always returns default valid result"() { - given: 'Sample metadata resolver and validation placeholderResolverService with no validators' + given: 'Sample metadata resolver and validation service with no validators' def resolver = Mock(MetadataResolver) @Subject def validationService = new MetadataResolverValidationService(null) @@ -24,7 +24,7 @@ class MetadataResolverValidationServiceTests extends Specification { } def "Validation service with one validator not supporting the type of resolver returns default valid result"() { - given: 'Sample metadata resolver and validation placeholderResolverService with one validator not supporting that type' + 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 @@ -39,7 +39,7 @@ class MetadataResolverValidationServiceTests extends Specification { } def "Validation service with one validator supporting the type of resolver but fails its validation"() { - given: 'Sample metadata resolver and validation placeholderResolverService with one validator supporting that type' + given: 'Sample metadata resolver and validation service with one validator supporting that type' def resolver = Mock(MetadataResolver) def validator = Mock(MetadataResolverValidator) validator.supports(_) >> true @@ -55,7 +55,7 @@ class MetadataResolverValidationServiceTests extends Specification { } def "Validation service with with two validators supporting the type of resolver, first fails, second passes validation"() { - given: 'Sample metadata resolver and validation placeholderResolverService with two validators supporting that type' + given: 'Sample metadata resolver and validation service with two validators supporting that type' def resolver = Mock(MetadataResolver) def validator1 = Mock(MetadataResolverValidator) validator1.supports(_) >> true @@ -74,7 +74,7 @@ class MetadataResolverValidationServiceTests extends Specification { } def "Validation service with with two validators, only one supporting the type of resolver, passes validation"() { - given: 'Sample metadata resolver and validation placeholderResolverService with two validators, with one supporting that type' + 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 From 31f2fc745a7584958d8019fbfbfe9807da93700d Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 09:37:59 -0400 Subject: [PATCH 10/25] SHIBUI-836: wip --- ...aceholderValueResolvingServiceTests.groovy | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy new file mode 100644 index 000000000..fc0f06c1d --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy @@ -0,0 +1,25 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import spock.lang.Specification +import spock.lang.Subject + +@ContextConfiguration(classes=[PlaceholderResolverComponentsConfiguration]) +class TokenPlaceholderValueResolvingServiceTests extends Specification { + + @Autowired + @Subject + TokenPlaceholderValueResolvingService placeholderValueResolvingService + + def "resolves correctly existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { + when: + def idpHome = placeholderValueResolvingService.resolveValueFromTokenPlaceholder('%{idp.home}') + + then: + idpHome + } + + +} From 4916b94013a649b100a874d0471ba5fc404fff6e Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 10:46:04 -0400 Subject: [PATCH 11/25] SHIBUI-836: tests wip --- ...holderTokenAwareValueResolvingService.java | 21 ++++++++--- ...TokenPlaceholderValueResolvingService.java | 2 +- ...aceholderValueResolvingServiceTests.groovy | 37 +++++++++++++++---- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index b4c6fd42a..5af4e793e 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -19,15 +19,26 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok private PropertyResolver propertyResolver; + private static final String SHIB_IDP_PLACEHOLDER_PREEFIX = "%{"; + + private static final String STANDART_PLACEHOLDER_PREFIX = "${"; + ShibbolethPlaceholderTokenAwareValueResolvingService(PropertyResolver propertyResolver) { this.propertyResolver = propertyResolver; } @Override - public String resolveValueFromTokenPlaceholder(String tokenPlaceholder) { - requireNonNull(tokenPlaceholder, "tokenPlaceholder must not be null"); - tokenPlaceholder.replace("%{", "${"); - - return null; + public String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder) { + requireNonNull(potentialTokenPlaceholder, "potentialTokenPlaceholder must not be null"); + if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREEFIX)) { + String normalizedTokenPlaceholder = + potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREEFIX, STANDART_PLACEHOLDER_PREFIX); + //This call might result in IllegalArgumentException if it's unable to resolve passed in property(ies) + //e.g. due to bad data sent, etc. This is OK, as passing correct data and ensuring that + //property values are correctly set is the responsibility of the software operator + return this.propertyResolver.resolveRequiredPlaceholders(normalizedTokenPlaceholder); + } + //No token placeholders, just return the given data as is + return potentialTokenPlaceholder; } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java index 0df2f0ca0..264ccc935 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java @@ -10,7 +10,7 @@ @FunctionalInterface public interface TokenPlaceholderValueResolvingService { - String resolveValueFromTokenPlaceholder(String tokenPlaceholder); + String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder); static TokenPlaceholderValueResolvingService shibbolethPlaceholderAware(PropertyResolver propertyResolver) { return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertyResolver); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy index fc0f06c1d..1046bc9f1 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy @@ -2,24 +2,47 @@ package edu.internet2.tier.shibboleth.admin.ui.service import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.util.TestPropertyValues +import org.springframework.core.env.ConfigurableEnvironment import org.springframework.test.context.ContextConfiguration + import spock.lang.Specification import spock.lang.Subject -@ContextConfiguration(classes=[PlaceholderResolverComponentsConfiguration]) +import static edu.internet2.tier.shibboleth.admin.ui.service.TestProps.IDP_HOME +import static edu.internet2.tier.shibboleth.admin.ui.service.TestProps.REFRESH_INTERVAL + + +/** + * @author Dmitriy Kopylenko + */ +@ContextConfiguration(classes = [PlaceholderResolverComponentsConfiguration]) class TokenPlaceholderValueResolvingServiceTests extends Specification { @Autowired @Subject - TokenPlaceholderValueResolvingService placeholderValueResolvingService + TokenPlaceholderValueResolvingService serviceUnderTest - def "resolves correctly existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { - when: - def idpHome = placeholderValueResolvingService.resolveValueFromTokenPlaceholder('%{idp.home}') + @Autowired + ConfigurableEnvironment environment - then: - idpHome + def setup() { + def propPairs = ["idp.home=$IDP_HOME".toString(), "refresh.interval=$REFRESH_INTERVAL".toString()] + TestPropertyValues.of(propPairs).applyTo(environment) } + def "resolves correctly existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { + when: 'Valid placeholder token is passed for which property values are defined' + def idpHome = serviceUnderTest.resolveValueFromTokenPlaceholder('%{idp.home}') + def refreshInterval = serviceUnderTest.resolveValueFromTokenPlaceholder('%{refresh.interval}') + + then: 'Correct property value resolution is performed' + idpHome == IDP_HOME + refreshInterval == REFRESH_INTERVAL + } +} +class TestProps { + static final IDP_HOME = '/tmp/test/idp' + static final REFRESH_INTERVAL = 'PT5M' } From 72eaf873e06eb2be07ebf3dcc315c1f2bb567da3 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 11:38:54 -0400 Subject: [PATCH 12/25] SHIBUI-836: clean up --- .../admin/ui/ShibbolethUiApplication.java | 19 ------------ ...lverPropertyPlaceholderValuesReplacer.java | 17 ----------- ...ertyPlaceholderValuesResolvingService.java | 29 ------------------- 3 files changed, 65 deletions(-) delete mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java delete mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java index aa19896ef..1fc74cf9d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/ShibbolethUiApplication.java @@ -1,10 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; -import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; -import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -13,8 +10,6 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.context.annotation.Profile; import org.springframework.context.event.EventListener; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.env.PropertyResolver; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.stereotype.Component; @@ -41,24 +36,10 @@ public static class MetadataResolversResourceIdEmitter { @Autowired MetadataResolverRepository metadataResolverRepository; - @Value("${idp.home}") - String idpHome; - - @Autowired - PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer; - - @Autowired - PropertyResolver propertyResolver; - @EventListener void showMetadataResolversResourceIds(ApplicationStartedEvent e) { metadataResolverRepository.findAll() .forEach(it -> System.out.println(String.format("MetadataResolver [%s: %s]", it.getName(), it.getResourceId()))); - - System.out.println("IDP HOME: " + idpHome); - String rawValue = "%{idp.home}/metadata/file.xml"; - String resolved = propertyResolver.resolvePlaceholders(rawValue.replace("%{", "${")); - TokenPlaceholderValueResolvingService service = TokenPlaceholderResolvers.placeholderResolverService(); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java deleted file mode 100644 index 10887e97f..000000000 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesReplacer.java +++ /dev/null @@ -1,17 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; - -/** - * An SPI to resolve and convert data for different types of {@link MetadataResolver}s from possible provided '%{}' placeholders - *

- * Typical usage is - multiple replacers for concrete type of resolvers are configured in Spring Application Context, - * aggregated by {@link MetadataResolverPropertyPlaceholderValuesResolvingService} facade and then that facade is injected into upstream consumers of it - * such as REST controllers, etc. - * - * @author Dmitriy Kopylenko - */ -public interface MetadataResolverPropertyPlaceholderValuesReplacer { - - boolean supports(T metadataResolver); - - void replacePlaceholderValuesIfResolvableOrFail(T metadataResolver); -} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java deleted file mode 100644 index e7639cfde..000000000 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/MetadataResolverPropertyPlaceholderValuesResolvingService.java +++ /dev/null @@ -1,29 +0,0 @@ -package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers; - -import java.util.ArrayList; -import java.util.List; - -/** - * A facade that aggregates {@link MetadataResolverPropertyPlaceholderValuesReplacer}s available to call just one of them supporting the type of a given resolver. - * If no {@link MetadataResolverPropertyPlaceholderValuesReplacer}s are configured, considers a noop. - * - * Uses chain-of-responsibility design pattern - * - * @author Dmitriy Kopylenko - */ -public class MetadataResolverPropertyPlaceholderValuesResolvingService { - - private List> replacers; - - public MetadataResolverPropertyPlaceholderValuesResolvingService(List> replacers) { - this.replacers = replacers != null ? replacers : new ArrayList<>(); - } - - public void replacePlacehoderValuesOrFail(T metadataResolver) { - this.replacers - .stream() - .filter(r -> r.supports(metadataResolver)) - .findFirst() - .ifPresent(r -> r.replacePlaceholderValuesIfResolvableOrFail(metadataResolver)); - } -} From 978a676300c083ec65affd1992491c9358a43303 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 11:42:06 -0400 Subject: [PATCH 13/25] SHIBUI-836: clean up --- ...TokenPlaceholderValueResolvingServiceTests.groovy | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy index 1046bc9f1..0362d50e2 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy @@ -9,10 +9,6 @@ import org.springframework.test.context.ContextConfiguration import spock.lang.Specification import spock.lang.Subject -import static edu.internet2.tier.shibboleth.admin.ui.service.TestProps.IDP_HOME -import static edu.internet2.tier.shibboleth.admin.ui.service.TestProps.REFRESH_INTERVAL - - /** * @author Dmitriy Kopylenko */ @@ -26,6 +22,9 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { @Autowired ConfigurableEnvironment environment + static final IDP_HOME = '/tmp/test/idp' + static final REFRESH_INTERVAL = 'PT5M' + def setup() { def propPairs = ["idp.home=$IDP_HOME".toString(), "refresh.interval=$REFRESH_INTERVAL".toString()] TestPropertyValues.of(propPairs).applyTo(environment) @@ -41,8 +40,3 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { refreshInterval == REFRESH_INTERVAL } } - -class TestProps { - static final IDP_HOME = '/tmp/test/idp' - static final REFRESH_INTERVAL = 'PT5M' -} From f0703063fb89c0170c2a78a9526f9512efc910f1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 12:10:01 -0400 Subject: [PATCH 14/25] SHIBUI-836: tests --- ...holderTokenAwareValueResolvingService.java | 9 +++- ...aceholderValueResolvingServiceTests.groovy | 41 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 5af4e793e..baca61749 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -36,7 +36,14 @@ public String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder) //This call might result in IllegalArgumentException if it's unable to resolve passed in property(ies) //e.g. due to bad data sent, etc. This is OK, as passing correct data and ensuring that //property values are correctly set is the responsibility of the software operator - return this.propertyResolver.resolveRequiredPlaceholders(normalizedTokenPlaceholder); + String resolved = this.propertyResolver.resolveRequiredPlaceholders(normalizedTokenPlaceholder); + + //Indicates that malformed values such as %{incomplete.token are passed. Spring won't resolve and return + //the value as is. Just change it back to the original shib-style token and return. + if(resolved.equals(normalizedTokenPlaceholder)) { + return resolved.replace(STANDART_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREEFIX); + } + return resolved; } //No token placeholders, just return the given data as is return potentialTokenPlaceholder; diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy index 0362d50e2..36837694c 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy @@ -24,6 +24,7 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { static final IDP_HOME = '/tmp/test/idp' static final REFRESH_INTERVAL = 'PT5M' + static final PLAIN_VALUE = 'Plain String value' def setup() { def propPairs = ["idp.home=$IDP_HOME".toString(), "refresh.interval=$REFRESH_INTERVAL".toString()] @@ -31,7 +32,7 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { } def "resolves correctly existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { - when: 'Valid placeholder token is passed for which property values are defined' + when: 'Valid placeholder token is passed in for which property values are defined' def idpHome = serviceUnderTest.resolveValueFromTokenPlaceholder('%{idp.home}') def refreshInterval = serviceUnderTest.resolveValueFromTokenPlaceholder('%{refresh.interval}') @@ -39,4 +40,42 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { idpHome == IDP_HOME refreshInterval == REFRESH_INTERVAL } + + def "returns value as is if no well-formed shibboleth idp style placeholder tokens: %{} are passed in"() { + when: 'Plain value without placeholder token is passed in' + def idpHome = serviceUnderTest.resolveValueFromTokenPlaceholder(IDP_HOME) + def plainValue = serviceUnderTest.resolveValueFromTokenPlaceholder(PLAIN_VALUE) + + then: 'Value returned as is' + idpHome == IDP_HOME + plainValue == PLAIN_VALUE + + when: 'Malformed placeholder value is passed in' + plainValue = serviceUnderTest.resolveValueFromTokenPlaceholder('%{malformed.value') + + then: + plainValue == '%{malformed.value' + } + + def "Throws IllegalArgumentException for unresolvable properties"() { + when: 'Valid placeholder token is passed in for which property values are undefined' + serviceUnderTest.resolveValueFromTokenPlaceholder("%{i.am.not.defined}") + + then: + thrown IllegalArgumentException + + when: 'Combination of resolvable and unresolvable tokens are passed in' + serviceUnderTest.resolveValueFromTokenPlaceholder("%{idp.home}/%{i.am.not.defined}") + + then: + thrown IllegalArgumentException + } + + def "resolves correctly combination of existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { + when: 'Valid placeholder token is passed in for which property values are defined' + def combinedValue = serviceUnderTest.resolveValueFromTokenPlaceholder('%{idp.home} AND %{refresh.interval}') + + then: 'Correct combined property values resolution is performed' + combinedValue == "$IDP_HOME AND $REFRESH_INTERVAL" + } } From c688c14d2c83965d92ff0fe5401d98d0526cfc03 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 14:30:21 -0400 Subject: [PATCH 15/25] SHIBUI-836: wip --- ...hibbolethPlaceholderTokenAwareValueResolvingService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index baca61749..242027773 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -29,7 +29,11 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok @Override public String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder) { - requireNonNull(potentialTokenPlaceholder, "potentialTokenPlaceholder must not be null"); + //Ignore nulls. + if(potentialTokenPlaceholder == null) { + return potentialTokenPlaceholder; + } + if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREEFIX)) { String normalizedTokenPlaceholder = potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREEFIX, STANDART_PLACEHOLDER_PREFIX); From 712b143695b8ab850ffb24332224d0501b2603a1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 15:55:49 -0400 Subject: [PATCH 16/25] SHIBUI-836 --- ...penSamlFileBackedHTTPMetadataResolver.java | 8 ++--- ...SamlMetadataResolverConstructorHelper.java | 29 ++++++++++++------- .../MetadataResolverConverterServiceImpl.java | 11 +++++-- ...holderTokenAwareValueResolvingService.java | 2 +- ...TokenPlaceholderValueResolvingService.java | 2 +- ...aceholderValueResolvingServiceTests.groovy | 16 +++++----- .../admin/ui/util/TestObjectGenerator.groovy | 2 +- backend/src/test/resources/conf/278.2.xml | 2 +- backend/src/test/resources/conf/278.xml | 2 +- backend/src/test/resources/conf/532.xml | 2 +- 10 files changed, 43 insertions(+), 33 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java index 7327458eb..04c223bc0 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlFileBackedHTTPMetadataResolver.java @@ -1,7 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.opensaml; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver; -import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; import net.shibboleth.utilities.java.support.xml.ParserPool; @@ -40,11 +39,10 @@ public OpenSamlFileBackedHTTPMetadataResolver(ParserPool parserPool, OpenSamlMetadataResolverConstructorHelper.updateOpenSamlMetadataResolverFromReloadableMetadataResolverAttributes( this, sourceResolver.getReloadableMetadataResolverAttributes(), parserPool); - //TODO: complete resolving placeholders everywhere - //This might throw runtime exception if unable to resolve placeholders sent from higher layers - this.setBackupFile(placeholderResolverService().resolveValueFromTokenPlaceholder(sourceResolver.getBackingFile())); + this.setBackupFile(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(sourceResolver.getBackingFile())); this.setBackupFileInitNextRefreshDelay(toMillis(placeholderResolverService() - .resolveValueFromTokenPlaceholder(sourceResolver.getBackupFileInitNextRefreshDelay()))); + .resolveValueFromPossibleTokenPlaceholder(sourceResolver.getBackupFileInitNextRefreshDelay()))); this.setInitializeFromBackupFile(sourceResolver.getInitializeFromBackupFile()); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java index 9d0383c11..d52e47448 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/resolvers/opensaml/OpenSamlMetadataResolverConstructorHelper.java @@ -3,7 +3,6 @@ import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.DynamicMetadataResolverAttributes; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.HttpMetadataResolverAttributes; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.ReloadableMetadataResolverAttributes; -import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import net.shibboleth.utilities.java.support.xml.ParserPool; import org.opensaml.saml.metadata.resolver.MetadataResolver; import org.opensaml.saml.metadata.resolver.impl.AbstractDynamicMetadataResolver; @@ -23,11 +22,14 @@ public static void updateOpenSamlMetadataResolverFromDynamicMetadataResolverAttr AbstractDynamicMetadataResolver dynamicMetadataResolver = (AbstractDynamicMetadataResolver) metadataResolver; if (attributes.getBackgroundInitializationFromCacheDelay() != null) { - dynamicMetadataResolver.setBackgroundInitializationFromCacheDelay(toMillis(attributes.getBackgroundInitializationFromCacheDelay())); + dynamicMetadataResolver + .setBackgroundInitializationFromCacheDelay(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getBackgroundInitializationFromCacheDelay()))); } if (attributes.getCleanupTaskInterval() != null) { - dynamicMetadataResolver.setCleanupTaskInterval(toMillis(attributes.getCleanupTaskInterval())); + dynamicMetadataResolver.setCleanupTaskInterval(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getCleanupTaskInterval()))); } if (attributes.getInitializeFromPersistentCacheInBackground()) { @@ -35,19 +37,23 @@ public static void updateOpenSamlMetadataResolverFromDynamicMetadataResolverAttr } if (attributes.getMaxCacheDuration() != null) { - dynamicMetadataResolver.setMaxCacheDuration(toMillis(attributes.getMaxCacheDuration())); + dynamicMetadataResolver.setMaxCacheDuration(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getMaxCacheDuration()))); } if (attributes.getMaxIdleEntityData() != null) { - dynamicMetadataResolver.setMaxIdleEntityData(toMillis(attributes.getMaxIdleEntityData())); + dynamicMetadataResolver.setMaxIdleEntityData(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getMaxIdleEntityData()))); } if (attributes.getMinCacheDuration() != null) { - dynamicMetadataResolver.setMinCacheDuration(toMillis(attributes.getMinCacheDuration())); + dynamicMetadataResolver.setMinCacheDuration(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getMinCacheDuration()))); } if (attributes.getBackgroundInitializationFromCacheDelay() != null) { - dynamicMetadataResolver.setBackgroundInitializationFromCacheDelay(toMillis(attributes.getBackgroundInitializationFromCacheDelay())); + dynamicMetadataResolver.setBackgroundInitializationFromCacheDelay(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getBackgroundInitializationFromCacheDelay()))); } if (attributes.getRefreshDelayFactor() != null) { @@ -87,18 +93,19 @@ public static void updateOpenSamlMetadataResolverFromReloadableMetadataResolverA //TODO: This takes a ParserPool. We've got a ParserPoolRef in attributes.getParserPoolRef(). Should we use it for anything? reloadingMetadataResolver.setParserPool(parserPool); - //TODO: finish placeholder resolving if (attributes != null) { if (attributes.getExpirationWarningThreshold() != null) { reloadingMetadataResolver .setExpirationWarningThreshold(toMillis(placeholderResolverService() - .resolveValueFromTokenPlaceholder(attributes.getExpirationWarningThreshold()))); + .resolveValueFromPossibleTokenPlaceholder(attributes.getExpirationWarningThreshold()))); } if (attributes.getMaxRefreshDelay() != null) { - reloadingMetadataResolver.setMaxRefreshDelay(toMillis(attributes.getMaxRefreshDelay())); + reloadingMetadataResolver.setMaxRefreshDelay(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getMaxRefreshDelay()))); } if (attributes.getMinRefreshDelay() != null) { - reloadingMetadataResolver.setMinRefreshDelay(toMillis(attributes.getMinRefreshDelay())); + reloadingMetadataResolver.setMinRefreshDelay(toMillis(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(attributes.getMinRefreshDelay()))); } if (attributes.getResolveViaPredicatesOnly() != null) { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java index 4ae0d07d2..b1147fa3d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/MetadataResolverConverterServiceImpl.java @@ -28,6 +28,8 @@ import java.io.IOException; import java.net.URL; +import static edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers.placeholderResolverService; + /** * @author Bill Smith (wsmith@unicon.net) */ @@ -60,7 +62,8 @@ private OpenSamlFileBackedHTTPMetadataResolver convertToOpenSamlRepresentation(F private OpenSamlFilesystemMetadataResolver convertToOpenSamlRepresentation(FilesystemMetadataResolver resolver) throws IOException, ResolverException, ComponentInitializationException { IndexWriter indexWriter = indexWriterService.getIndexWriter(resolver.getResourceId()); - URL url = Thread.currentThread().getContextClassLoader().getResource(resolver.getMetadataFile()); + URL url = Thread.currentThread().getContextClassLoader().getResource(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(resolver.getMetadataFile())); File metadataFile = new File(url.getPath()); OpenSamlFilesystemMetadataResolver openSamlResolver = new OpenSamlFilesystemMetadataResolver(openSamlObjects.getParserPool(), @@ -76,7 +79,8 @@ private OpenSamlLocalDynamicMetadataResolver convertToOpenSamlRepresentation(Loc XMLObjectLoadSaveManager manager = null; try { - manager = new FilesystemLoadSaveManager(resolver.getSourceDirectory()); + manager = new FilesystemLoadSaveManager(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(resolver.getSourceDirectory())); } catch (ConstraintViolationException e) { // the base directory string instance was null or empty //TODO: What should we do here? Currently, this causes a test to fail. @@ -96,7 +100,8 @@ private OpenSamlResourceBackedMetadataResolver convertToOpenSamlRepresentation(R //TODO: What sort of resource type should be created here? URL? break; case CLASSPATH: - resource = ResourceHelper.of(new ClassPathResource(resolver.getClasspathMetadataResource().getFile())); + resource = ResourceHelper.of(new ClassPathResource(placeholderResolverService() + .resolveValueFromPossibleTokenPlaceholder(resolver.getClasspathMetadataResource().getFile()))); break; default: throw new RuntimeException("Unsupported resource type!"); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 242027773..605abd540 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -28,7 +28,7 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok } @Override - public String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder) { + public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder) { //Ignore nulls. if(potentialTokenPlaceholder == null) { return potentialTokenPlaceholder; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java index 264ccc935..689ffbcbb 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java @@ -10,7 +10,7 @@ @FunctionalInterface public interface TokenPlaceholderValueResolvingService { - String resolveValueFromTokenPlaceholder(String potentialTokenPlaceholder); + String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder); static TokenPlaceholderValueResolvingService shibbolethPlaceholderAware(PropertyResolver propertyResolver) { return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertyResolver); diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy index 36837694c..8e3ba09f7 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingServiceTests.groovy @@ -33,8 +33,8 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { def "resolves correctly existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { when: 'Valid placeholder token is passed in for which property values are defined' - def idpHome = serviceUnderTest.resolveValueFromTokenPlaceholder('%{idp.home}') - def refreshInterval = serviceUnderTest.resolveValueFromTokenPlaceholder('%{refresh.interval}') + def idpHome = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder('%{idp.home}') + def refreshInterval = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder('%{refresh.interval}') then: 'Correct property value resolution is performed' idpHome == IDP_HOME @@ -43,15 +43,15 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { def "returns value as is if no well-formed shibboleth idp style placeholder tokens: %{} are passed in"() { when: 'Plain value without placeholder token is passed in' - def idpHome = serviceUnderTest.resolveValueFromTokenPlaceholder(IDP_HOME) - def plainValue = serviceUnderTest.resolveValueFromTokenPlaceholder(PLAIN_VALUE) + def idpHome = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder(IDP_HOME) + def plainValue = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder(PLAIN_VALUE) then: 'Value returned as is' idpHome == IDP_HOME plainValue == PLAIN_VALUE when: 'Malformed placeholder value is passed in' - plainValue = serviceUnderTest.resolveValueFromTokenPlaceholder('%{malformed.value') + plainValue = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder('%{malformed.value') then: plainValue == '%{malformed.value' @@ -59,13 +59,13 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { def "Throws IllegalArgumentException for unresolvable properties"() { when: 'Valid placeholder token is passed in for which property values are undefined' - serviceUnderTest.resolveValueFromTokenPlaceholder("%{i.am.not.defined}") + serviceUnderTest.resolveValueFromPossibleTokenPlaceholder("%{i.am.not.defined}") then: thrown IllegalArgumentException when: 'Combination of resolvable and unresolvable tokens are passed in' - serviceUnderTest.resolveValueFromTokenPlaceholder("%{idp.home}/%{i.am.not.defined}") + serviceUnderTest.resolveValueFromPossibleTokenPlaceholder("%{idp.home}/%{i.am.not.defined}") then: thrown IllegalArgumentException @@ -73,7 +73,7 @@ class TokenPlaceholderValueResolvingServiceTests extends Specification { def "resolves correctly combination of existing properties from well-formed shibboleth idp style placeholder tokens: %{}"() { when: 'Valid placeholder token is passed in for which property values are defined' - def combinedValue = serviceUnderTest.resolveValueFromTokenPlaceholder('%{idp.home} AND %{refresh.interval}') + def combinedValue = serviceUnderTest.resolveValueFromPossibleTokenPlaceholder('%{idp.home} AND %{refresh.interval}') then: 'Correct combined property values resolution is performed' combinedValue == "$IDP_HOME AND $REFRESH_INTERVAL" diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy index 7510f9929..3faa17cdf 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/util/TestObjectGenerator.groovy @@ -456,7 +456,7 @@ class TestObjectGenerator { new FileBackedHttpMetadataResolver().with { it.name = 'HTTPMetadata' it.xmlId = 'HTTPMetadata' - it.backingFile = 'unicon.xml' + it.backingFile = '%{idp.home}/metadata/metadata.xml' it.metadataURL = 'https://idp.unicon.net/idp/shibboleth' it.reloadableMetadataResolverAttributes = new ReloadableMetadataResolverAttributes().with { diff --git a/backend/src/test/resources/conf/278.2.xml b/backend/src/test/resources/conf/278.2.xml index 2b71b5ed1..a7adef87f 100644 --- a/backend/src/test/resources/conf/278.2.xml +++ b/backend/src/test/resources/conf/278.2.xml @@ -38,7 +38,7 @@ Date: Wed, 12 Sep 2018 16:00:24 -0400 Subject: [PATCH 17/25] SHIBUI-836: polishing --- .../tier/shibboleth/admin/util/TokenPlaceholderResolvers.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java index f65737be2..8c8b2898d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java @@ -1,8 +1,6 @@ package edu.internet2.tier.shibboleth.admin.util; import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; public class TokenPlaceholderResolvers { From 9d4b637432a1d7638fdeb7b0c8a766053b4d27c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:01:42 -0400 Subject: [PATCH 18/25] SHIBUI-836: polishing --- .../ShibbolethPlaceholderTokenAwareValueResolvingService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 605abd540..14725f4fd 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -2,9 +2,6 @@ import org.springframework.core.env.PropertyResolver; -import java.util.Objects; - -import static java.util.Objects.requireNonNull; /** * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's default property resolver From 1697c705a67e570389995b19b7deda6fbd203e9c Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:02:14 -0400 Subject: [PATCH 19/25] SHIBUI-836: polishing --- .../ShibbolethPlaceholderTokenAwareValueResolvingService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 14725f4fd..9ba4d8e82 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -8,7 +8,7 @@ * which understands and replaces Shibboleth Idp specific placeholder prefix of '%{' with standard Spring's placeholder * prefix of '${' before resolving. * - * If passed it value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. + * If passed in value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. * * @author Dmitriy Kopylenko */ From 4c536047e091e64eb455a7f87a3c10cf5aca0285 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:03:29 -0400 Subject: [PATCH 20/25] SHIBUI-836: polishing --- ...hibbolethPlaceholderTokenAwareValueResolvingService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 9ba4d8e82..e869c626f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -18,7 +18,7 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok private static final String SHIB_IDP_PLACEHOLDER_PREEFIX = "%{"; - private static final String STANDART_PLACEHOLDER_PREFIX = "${"; + private static final String STANDARD_PLACEHOLDER_PREFIX = "${"; ShibbolethPlaceholderTokenAwareValueResolvingService(PropertyResolver propertyResolver) { this.propertyResolver = propertyResolver; @@ -33,7 +33,7 @@ public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlac if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREEFIX)) { String normalizedTokenPlaceholder = - potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREEFIX, STANDART_PLACEHOLDER_PREFIX); + potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREEFIX, STANDARD_PLACEHOLDER_PREFIX); //This call might result in IllegalArgumentException if it's unable to resolve passed in property(ies) //e.g. due to bad data sent, etc. This is OK, as passing correct data and ensuring that //property values are correctly set is the responsibility of the software operator @@ -42,7 +42,7 @@ public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlac //Indicates that malformed values such as %{incomplete.token are passed. Spring won't resolve and return //the value as is. Just change it back to the original shib-style token and return. if(resolved.equals(normalizedTokenPlaceholder)) { - return resolved.replace(STANDART_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREEFIX); + return resolved.replace(STANDARD_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREEFIX); } return resolved; } From 1136a01df6e41ac3392f44407feeae1055ba200c Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:03:52 -0400 Subject: [PATCH 21/25] SHIBUI-836: polishing --- ...bbolethPlaceholderTokenAwareValueResolvingService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index e869c626f..52ca767f0 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -16,7 +16,7 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok private PropertyResolver propertyResolver; - private static final String SHIB_IDP_PLACEHOLDER_PREEFIX = "%{"; + private static final String SHIB_IDP_PLACEHOLDER_PREFIX = "%{"; private static final String STANDARD_PLACEHOLDER_PREFIX = "${"; @@ -31,9 +31,9 @@ public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlac return potentialTokenPlaceholder; } - if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREEFIX)) { + if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREFIX)) { String normalizedTokenPlaceholder = - potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREEFIX, STANDARD_PLACEHOLDER_PREFIX); + potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREFIX, STANDARD_PLACEHOLDER_PREFIX); //This call might result in IllegalArgumentException if it's unable to resolve passed in property(ies) //e.g. due to bad data sent, etc. This is OK, as passing correct data and ensuring that //property values are correctly set is the responsibility of the software operator @@ -42,7 +42,7 @@ public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlac //Indicates that malformed values such as %{incomplete.token are passed. Spring won't resolve and return //the value as is. Just change it back to the original shib-style token and return. if(resolved.equals(normalizedTokenPlaceholder)) { - return resolved.replace(STANDARD_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREEFIX); + return resolved.replace(STANDARD_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREFIX); } return resolved; } From 7c3b9347bbddcc3b3fc20257cbd67dc7cc0acaa1 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:16:33 -0400 Subject: [PATCH 22/25] SHIBUI-836: polishing --- .../IdpHomeValueSettingEnvironmentPostProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java index 814a797c2..97eb0bd4f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java @@ -17,9 +17,11 @@ import java.util.Map; /** - * Spring Boot Environment Post Processor setting the value for idp.home property to an abstract temp directory + * Spring Boot Environment Post Processor setting the value for idp.home property to a temp directory * if no IDP_HOME environment variable has been set already. * + * Also creates IDP_HOME/metadata directory if no such directory already exixst. + * * @author Dmitriy Kopylenko */ public class IdpHomeValueSettingEnvironmentPostProcessor implements EnvironmentPostProcessor { From 347da0d13927d20d650096e7e7b16078167aac19 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Wed, 12 Sep 2018 16:23:52 -0400 Subject: [PATCH 23/25] SHIBUI-836: typo --- .../IdpHomeValueSettingEnvironmentPostProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java index 97eb0bd4f..7474af1f5 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java @@ -20,7 +20,7 @@ * Spring Boot Environment Post Processor setting the value for idp.home property to a temp directory * if no IDP_HOME environment variable has been set already. * - * Also creates IDP_HOME/metadata directory if no such directory already exixst. + * Also creates IDP_HOME/metadata directory if no such directory already exists. * * @author Dmitriy Kopylenko */ From 3620e0afe6fb63afcbb76bc94e5e583b13003b53 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Thu, 13 Sep 2018 11:03:21 -0400 Subject: [PATCH 24/25] SHIBUI-836: fix test --- .../shibboleth/admin/ui/domain/EntityDescriptorTest.groovy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityDescriptorTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityDescriptorTest.groovy index 79a539086..5fe53b85b 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityDescriptorTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/EntityDescriptorTest.groovy @@ -2,6 +2,7 @@ package edu.internet2.tier.shibboleth.admin.ui.domain import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration +import edu.internet2.tier.shibboleth.admin.ui.configuration.PlaceholderResolverComponentsConfiguration 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.domain.resolvers.HttpMetadataResolverAttributes @@ -18,6 +19,7 @@ import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver 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.boot.test.context.SpringBootTest import org.springframework.boot.test.context.TestConfiguration import org.springframework.context.annotation.Bean import org.springframework.data.jpa.repository.config.EnableJpaRepositories @@ -31,7 +33,7 @@ import java.nio.file.Files * @author Bill Smith (wsmith@unicon.net) */ @DataJpaTest -@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration, MyConfig]) +@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, InternationalizationConfiguration, MyConfig, PlaceholderResolverComponentsConfiguration]) @EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"]) @EntityScan("edu.internet2.tier.shibboleth.admin.ui") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @@ -58,14 +60,13 @@ class EntityDescriptorTest extends Specification { def "entity descriptors properly marshall to xml"() { given: - def tempDir = Files.createTempDirectory('test') ((OpenSamlChainingMetadataResolver)metadataResolver).resolvers = [ new OpenSamlFileBackedHTTPMetadataResolver( openSamlObjects.parserPool, indexWriterService.getIndexWriter('testme'), new FileBackedHttpMetadataResolver( metadataURL: 'https://idp.unicon.net/idp/shibboleth', - backingFile: "${tempDir.toString()}/test.xml", + backingFile: "%{idp.home}/metadata/test.xml", reloadableMetadataResolverAttributes: new ReloadableMetadataResolverAttributes(), httpMetadataResolverAttributes: new HttpMetadataResolverAttributes() ) From 1d24a1d64cd18f89cd43bc5dbc27e9dc911a3060 Mon Sep 17 00:00:00 2001 From: Dmitriy Kopylenko Date: Tue, 18 Sep 2018 10:30:37 -0400 Subject: [PATCH 25/25] SHIBUI-836: Refactor based on code review --- ...holderResolverComponentsConfiguration.java | 6 +-- ...eValueSettingEnvironmentPostProcessor.java | 41 ++++++----------- ...holderTokenAwareValueResolvingService.java | 45 +++++-------------- ...TokenPlaceholderValueResolvingService.java | 6 ++- .../admin/util/TokenPlaceholderResolvers.java | 5 +++ 5 files changed, 37 insertions(+), 66 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java index 484675e3d..bd391e0d5 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/PlaceholderResolverComponentsConfiguration.java @@ -4,14 +4,14 @@ import edu.internet2.tier.shibboleth.admin.util.TokenPlaceholderResolvers; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.PropertyResolver; +import org.springframework.core.env.ConfigurableEnvironment; @Configuration public class PlaceholderResolverComponentsConfiguration { @Bean - public TokenPlaceholderValueResolvingService tokenPlaceholderValueResolvingService(PropertyResolver propertyResolver) { - return TokenPlaceholderValueResolvingService.shibbolethPlaceholderAware(propertyResolver); + public TokenPlaceholderValueResolvingService tokenPlaceholderValueResolvingService(ConfigurableEnvironment env) { + return TokenPlaceholderValueResolvingService.shibbolethPlaceholderPrefixAware(env.getPropertySources()); } @Bean diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java index 7474af1f5..8f8bd3499 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/postprocessors/IdpHomeValueSettingEnvironmentPostProcessor.java @@ -1,6 +1,5 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration.postprocessors; -import lombok.extern.log4j.Log4j2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; @@ -8,7 +7,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -20,8 +18,6 @@ * Spring Boot Environment Post Processor setting the value for idp.home property to a temp directory * if no IDP_HOME environment variable has been set already. * - * Also creates IDP_HOME/metadata directory if no such directory already exists. - * * @author Dmitriy Kopylenko */ public class IdpHomeValueSettingEnvironmentPostProcessor implements EnvironmentPostProcessor { @@ -34,31 +30,20 @@ public class IdpHomeValueSettingEnvironmentPostProcessor implements EnvironmentP @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - String existingIdpHome = environment.getProperty(IDP_HOME_PROP); - Path metadataSubDir = Paths.get(existingIdpHome, METADATA_DIR); - if (existingIdpHome != null) { - if (!Files.exists(metadataSubDir)) { - try { - Files.createDirectories(metadataSubDir); - } catch (IOException e) { - LOGGER.error(e.getMessage()); - throw new RuntimeException(e); - } + if(environment.getProperty(IDP_HOME_PROP) == null) { + Map map = new HashMap<>(1); + try { + Path tempDir = Files.createTempDirectory(null); + tempDir.toFile().deleteOnExit(); + String tempDirName = tempDir.toAbsolutePath().toString(); + Path tempMetadataSubDir = Paths.get(tempDirName, METADATA_DIR); + Files.createDirectories(tempMetadataSubDir); + map.put(IDP_HOME_PROP, tempDirName); + } catch (IOException e) { + LOGGER.error(e.getMessage()); + throw new RuntimeException(e); } - return; - } - - Map map = new HashMap<>(1); - try { - Path tempDir = Files.createTempDirectory(String.format("%s.%s.", "shibui", IDP_HOME_PROP)); - String tempDirName = tempDir.toAbsolutePath().toString(); - Path tempMetadataSubDir = Paths.get(tempDirName, METADATA_DIR); - Files.createDirectories(tempMetadataSubDir); - map.put(IDP_HOME_PROP, tempDirName); - } catch (IOException e) { - LOGGER.error(e.getMessage()); - throw new RuntimeException(e); + environment.getPropertySources().addLast(new MapPropertySource("idp.home.propertysource", map)); } - environment.getPropertySources().addLast(new MapPropertySource("idp.home.propertysource", map)); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java index 52ca767f0..5ae9a60cc 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/ShibbolethPlaceholderTokenAwareValueResolvingService.java @@ -1,14 +1,14 @@ package edu.internet2.tier.shibboleth.admin.ui.service; import org.springframework.core.env.PropertyResolver; +import org.springframework.core.env.PropertySources; +import org.springframework.core.env.PropertySourcesPropertyResolver; /** - * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's default property resolver - * which understands and replaces Shibboleth Idp specific placeholder prefix of '%{' with standard Spring's placeholder - * prefix of '${' before resolving. - * - * If passed in value does not contain Shibboleth Idp '%{}' placeholder token, returns that value as is. + * Implementation of {@link TokenPlaceholderValueResolvingService} based on Spring Framework's property resolver which + * understands Shibboleth Idp custom placeholder prefix of %{ and can resolve property values from these + * placeholders against existing property sources. * * @author Dmitriy Kopylenko */ @@ -16,37 +16,16 @@ public class ShibbolethPlaceholderTokenAwareValueResolvingService implements Tok private PropertyResolver propertyResolver; - private static final String SHIB_IDP_PLACEHOLDER_PREFIX = "%{"; - - private static final String STANDARD_PLACEHOLDER_PREFIX = "${"; - - ShibbolethPlaceholderTokenAwareValueResolvingService(PropertyResolver propertyResolver) { - this.propertyResolver = propertyResolver; + ShibbolethPlaceholderTokenAwareValueResolvingService(PropertySources propertySources) { + PropertySourcesPropertyResolver propertySourcesPropertyResolver = new PropertySourcesPropertyResolver(propertySources); + propertySourcesPropertyResolver.setPlaceholderPrefix("%{"); + this.propertyResolver = propertySourcesPropertyResolver; } @Override public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder) { - //Ignore nulls. - if(potentialTokenPlaceholder == null) { - return potentialTokenPlaceholder; - } - - if(potentialTokenPlaceholder.contains(SHIB_IDP_PLACEHOLDER_PREFIX)) { - String normalizedTokenPlaceholder = - potentialTokenPlaceholder.replace(SHIB_IDP_PLACEHOLDER_PREFIX, STANDARD_PLACEHOLDER_PREFIX); - //This call might result in IllegalArgumentException if it's unable to resolve passed in property(ies) - //e.g. due to bad data sent, etc. This is OK, as passing correct data and ensuring that - //property values are correctly set is the responsibility of the software operator - String resolved = this.propertyResolver.resolveRequiredPlaceholders(normalizedTokenPlaceholder); - - //Indicates that malformed values such as %{incomplete.token are passed. Spring won't resolve and return - //the value as is. Just change it back to the original shib-style token and return. - if(resolved.equals(normalizedTokenPlaceholder)) { - return resolved.replace(STANDARD_PLACEHOLDER_PREFIX, SHIB_IDP_PLACEHOLDER_PREFIX); - } - return resolved; - } - //No token placeholders, just return the given data as is - return potentialTokenPlaceholder; + return potentialTokenPlaceholder != null + ? this.propertyResolver.resolveRequiredPlaceholders(potentialTokenPlaceholder) + : potentialTokenPlaceholder; } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java index 689ffbcbb..19d8217ff 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/TokenPlaceholderValueResolvingService.java @@ -1,6 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.service; import org.springframework.core.env.PropertyResolver; +import org.springframework.core.env.PropertySources; /** * Generic API to resolve values from arbitrary tokenized placeholders such as '%{token.placeholder}' etc. @@ -12,7 +13,8 @@ public interface TokenPlaceholderValueResolvingService { String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder); - static TokenPlaceholderValueResolvingService shibbolethPlaceholderAware(PropertyResolver propertyResolver) { - return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertyResolver); + + static TokenPlaceholderValueResolvingService shibbolethPlaceholderPrefixAware(PropertySources propertySources) { + return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertySources); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java index 8c8b2898d..9ac8947b7 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/util/TokenPlaceholderResolvers.java @@ -2,6 +2,11 @@ import edu.internet2.tier.shibboleth.admin.ui.service.TokenPlaceholderValueResolvingService; +/** + * Accessor facade class to expose {@link TokenPlaceholderValueResolvingService} to non-Spring-managed classes. + * + * @author Dmitriy Kopylenko + */ public class TokenPlaceholderResolvers { private static TokenPlaceholderValueResolvingService placeholderResolverService;