Skip to content

Commit

Permalink
Merge branch 'master' into SHIBUI-839
Browse files Browse the repository at this point in the history
  • Loading branch information
Bill Smith committed Sep 20, 2018
2 parents c62384f + e923d2d commit 19222e9
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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.ConfigurableEnvironment;

@Configuration
public class PlaceholderResolverComponentsConfiguration {

@Bean
public TokenPlaceholderValueResolvingService tokenPlaceholderValueResolvingService(ConfigurableEnvironment env) {
return TokenPlaceholderValueResolvingService.shibbolethPlaceholderPrefixAware(env.getPropertySources());
}

@Bean
public TokenPlaceholderResolvers tokenPlaceholderResolvers(TokenPlaceholderValueResolvingService service) {
return new TokenPlaceholderResolvers(service);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package edu.internet2.tier.shibboleth.admin.ui.configuration.postprocessors;

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.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 a temp directory
* if no IDP_HOME environment variable has been set already.
*
* @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) {
if(environment.getProperty(IDP_HOME_PROP) == null) {
Map<String, Object> 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);
}
environment.getPropertySources().addLast(new MapPropertySource("idp.home.propertysource", map));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,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)
Expand Down Expand Up @@ -45,8 +46,11 @@ public OpenSamlFileBackedHTTPMetadataResolver(ParserPool parserPool,
OpenSamlMetadataResolverConstructorHelper.updateOpenSamlMetadataResolverFromReloadableMetadataResolverAttributes(
this, sourceResolver.getReloadableMetadataResolverAttributes(), parserPool);

this.setBackupFile(sourceResolver.getBackingFile());
this.setBackupFileInitNextRefreshDelay(toMillis(sourceResolver.getBackupFileInitNextRefreshDelay()));
this.setBackupFile(placeholderResolverService()
.resolveValueFromPossibleTokenPlaceholder(sourceResolver.getBackingFile()));
this.setBackupFileInitNextRefreshDelay(toMillis(placeholderResolverService()
.resolveValueFromPossibleTokenPlaceholder(sourceResolver.getBackupFileInitNextRefreshDelay())));

this.setInitializeFromBackupFile(sourceResolver.getInitializeFromBackupFile());

this.setMetadataFilter(new MetadataFilterChain());
Expand All @@ -72,6 +76,7 @@ protected void processConditionalRetrievalHeaders(HttpResponse response) {
protected void initMetadataResolver() throws ComponentInitializationException {
super.initMetadataResolver();


delegate.addIndexedDescriptorsFromBackingStore(this.getBackingStore(),
this.sourceResolver.getResourceId(),
indexWriter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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)
Expand All @@ -21,31 +22,38 @@ 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()) {
dynamicMetadataResolver.setInitializeFromPersistentCacheInBackground(attributes.getInitializeFromPersistentCacheInBackground());
}

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) {
Expand Down Expand Up @@ -87,13 +95,17 @@ public static void updateOpenSamlMetadataResolverFromReloadableMetadataResolverA

if (attributes != null) {
if (attributes.getExpirationWarningThreshold() != null) {
reloadingMetadataResolver.setExpirationWarningThreshold(toMillis(attributes.getExpirationWarningThreshold()));
reloadingMetadataResolver
.setExpirationWarningThreshold(toMillis(placeholderResolverService()
.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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*/
Expand Down Expand Up @@ -59,7 +61,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(),
Expand All @@ -75,7 +78,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.
Expand All @@ -95,7 +99,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!");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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 property resolver which
* understands Shibboleth Idp custom placeholder prefix of <strong>%{</strong> and can resolve property values from these
* placeholders against existing property sources.
*
* @author Dmitriy Kopylenko
*/
public class ShibbolethPlaceholderTokenAwareValueResolvingService implements TokenPlaceholderValueResolvingService {

private PropertyResolver propertyResolver;

ShibbolethPlaceholderTokenAwareValueResolvingService(PropertySources propertySources) {
PropertySourcesPropertyResolver propertySourcesPropertyResolver = new PropertySourcesPropertyResolver(propertySources);
propertySourcesPropertyResolver.setPlaceholderPrefix("%{");
this.propertyResolver = propertySourcesPropertyResolver;
}

@Override
public String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder) {
return potentialTokenPlaceholder != null
? this.propertyResolver.resolveRequiredPlaceholders(potentialTokenPlaceholder)
: potentialTokenPlaceholder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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.
*
* @author Dmitriy Kopylenko
*/
@FunctionalInterface
public interface TokenPlaceholderValueResolvingService {

String resolveValueFromPossibleTokenPlaceholder(String potentialTokenPlaceholder);


static TokenPlaceholderValueResolvingService shibbolethPlaceholderPrefixAware(PropertySources propertySources) {
return new ShibbolethPlaceholderTokenAwareValueResolvingService(propertySources);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package edu.internet2.tier.shibboleth.admin.util;

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;

public TokenPlaceholderResolvers(TokenPlaceholderValueResolvingService service) {
TokenPlaceholderResolvers.placeholderResolverService = service;
}

public static TokenPlaceholderValueResolvingService placeholderResolverService() {
return placeholderResolverService;
}
}
2 changes: 2 additions & 0 deletions backend/src/main/resources/META-INF/spring.factories
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.boot.env.EnvironmentPostProcessor=\
edu.internet2.tier.shibboleth.admin.ui.configuration.postprocessors.IdpHomeValueSettingEnvironmentPostProcessor
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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()
)
Expand Down
Loading

0 comments on commit 19222e9

Please sign in to comment.