[java-identity-provider] branch main updated: OSJ-304: Support hash-based directory structure in LocalDynamic
Brent Putman
putmanb at georgetown.edu
Fri Nov 6 02:41:17 UTC 2020
This is an automated email from the git hooks/post-receive script.
putmanb pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=39427322864632ff12dc30bf398f3413a04bb8dc
The following commit(s) were added to refs/heads/main by this push:
new 394273228 OSJ-304: Support hash-based directory structure in LocalDynamic
394273228 is described below
commit 39427322864632ff12dc30bf398f3413a04bb8dc
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Thu Oct 29 20:24:57 2020 -0400
OSJ-304: Support hash-based directory structure in LocalDynamic
---
.../impl/LocalDynamicMetadataProviderParser.java | 136 +++++++++++++++++++--
.../LocalDynamicMetadataProviderParserTest.java | 134 ++++++++++++++++++--
.../profile/spring/relyingparty/metadata/beans.xml | 8 ++
...namicMissingSourceManagerAndSourceDirectory.xml | 12 ++
...DirectoryAndIntermediateLengthWithoutNumber.xml | 14 +++
...urceDirectoryAndIntermediateNumberAndLength.xml | 15 +++
...DirectoryAndIntermediateNumberWithoutLength.xml | 14 +++
...thSourceDirectoryAndIntermediateStrategyRef.xml | 14 +++
.../main/resources/schema/shibboleth-metadata.xsd | 59 +++++++++
9 files changed, 388 insertions(+), 18 deletions(-)
diff --git a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/LocalDynamicMetadataProviderParser.java b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/LocalDynamicMetadataProviderParser.java
index 1ccd34b0b..039f171a8 100644
--- a/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/LocalDynamicMetadataProviderParser.java
+++ b/idp-profile-spring/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/impl/LocalDynamicMetadataProviderParser.java
@@ -20,11 +20,14 @@ package net.shibboleth.idp.profile.spring.relyingparty.metadata.impl;
import javax.xml.namespace.QName;
import org.opensaml.core.xml.persist.FilesystemLoadSaveManager;
+import org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy;
+import org.opensaml.core.xml.persist.impl.SegmentingIntermediateDirectoryStrategy;
import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.opensaml.saml.metadata.resolver.impl.DefaultLocalDynamicSourceKeyGenerator;
import org.opensaml.saml.metadata.resolver.impl.LocalDynamicMetadataResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.parsing.Location;
import org.springframework.beans.factory.parsing.Problem;
@@ -66,20 +69,17 @@ public class LocalDynamicMetadataProviderParser extends AbstractDynamicMetadataP
Object sourceManagerRefOrBean = null;
if (element.hasAttributeNS(null, "sourceManagerRef")) {
sourceManagerRefOrBean = StringSupport.trimOrNull(element.getAttributeNS(null, "sourceManagerRef"));
- if (element.hasAttributeNS(null, "sourceDirectory")) {
- log.warn("Presence of sourceManagerRef will override sourceDirectory");
- }
+ checkAndLogSourceDirectoryOverrides(element);
} else if (element.hasAttributeNS(null, "sourceDirectory")) {
- final BeanDefinitionBuilder sourceManagerBuilder =
- BeanDefinitionBuilder.genericBeanDefinition(FilesystemLoadSaveManager.class);
- sourceManagerBuilder.addConstructorArgValue(
- StringSupport.trimOrNull(element.getAttributeNS(null, "sourceDirectory")));
- sourceManagerBuilder.addConstructorArgValue(Boolean.TRUE);
- sourceManagerRefOrBean = sourceManagerBuilder.getBeanDefinition();
-
+ // Default in source key generator if not supplied
+ boolean isDefaultSourceKeyGenerator = false;
if (sourceKeyGeneratorRefOrBean == null) {
sourceKeyGeneratorRefOrBean = new DefaultLocalDynamicSourceKeyGenerator(null, ".xml", null);
+ isDefaultSourceKeyGenerator = true;
}
+
+ sourceManagerRefOrBean = buildFilesystemManagerDefinition(element, parserContext,
+ isDefaultSourceKeyGenerator);
} else {
log.error("{} LocalDynamicMetadataProvider contained neither a sourceManagerRef nor a sourceDirectory",
parserContext.getReaderContext().getResource().getDescription());
@@ -102,4 +102,120 @@ public class LocalDynamicMetadataProviderParser extends AbstractDynamicMetadataP
}
+ /**
+ * Check and log the options related to 'sourceDirectory' which are being overridden by 'sourceManagerRef'.
+ *
+ * @param element the element being parsed
+ */
+ private void checkAndLogSourceDirectoryOverrides(final Element element) {
+ if (element.hasAttributeNS(null, "sourceDirectory")) {
+ log.warn("Presence of sourceManagerRef will override sourceDirectory");
+ }
+
+ if (element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentNumber")
+ || element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentLength")
+ || element.hasAttributeNS(null, "sourceDirectoryIntermediateStrategyRef")) {
+ log.warn("Presence of sourceManagerRef will override sourceDirectoryIntermediateSegmentNumber, "
+ + "sourceDirectoryIntermediateSegmentLength and sourceDirectoryIntermediateStrategyRef");
+ }
+ }
+
+ /**
+ * Build bean definition for {@link FilesystemLoadSaveManager} source manager.
+ *
+ * @param element the element being parsed
+ * @param parserContext the current parser context
+ * @param isDefaultSourceKeyGenerator whether the internal default source key manager is being used
+ *
+ * @return the bean definition for the filesystem source manager
+ */
+ private BeanDefinition buildFilesystemManagerDefinition(final Element element, final ParserContext parserContext,
+ final boolean isDefaultSourceKeyGenerator) {
+
+ final BeanDefinitionBuilder sourceManagerBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(FilesystemLoadSaveManager.class);
+
+ sourceManagerBuilder.addConstructorArgValue(
+ StringSupport.trimOrNull(element.getAttributeNS(null, "sourceDirectory")));
+
+ sourceManagerBuilder.addConstructorArgValue(Boolean.TRUE);
+
+ // Figure out intermediate directory strategy, if configured, and apply
+ processIntermediateDirectoryStrategy(element, parserContext, sourceManagerBuilder,
+ isDefaultSourceKeyGenerator);
+
+ return sourceManagerBuilder.getBeanDefinition();
+ }
+
+ /**
+ * Process options related to intermediate directory strategy and apply to the builder for the
+ * {@link FilesystemLoadSaveManager}.
+ *
+ * @param element the element being parsed
+ * @param parserContext the current parser context
+ * @param sourceManagerBuilder the source build manager for the FilesystemLoadSaveManager being built
+ * @param isDefaultSourceKeyGenerator whether the internal default source key manager is being used
+ */
+ private void processIntermediateDirectoryStrategy(final Element element, final ParserContext parserContext,
+ final BeanDefinitionBuilder sourceManagerBuilder, final boolean isDefaultSourceKeyGenerator) {
+
+ if (element.hasAttributeNS(null, "sourceDirectoryIntermediateStrategyRef")) {
+ sourceManagerBuilder.addConstructorArgReference(
+ StringSupport.trimOrNull(
+ element.getAttributeNS(null, "sourceDirectoryIntermediateStrategyRef")));
+ } else if (isDefaultSourceKeyGenerator) {
+ final BeanDefinition intermediateDirectoryStrategy =
+ checkAndBuildPassthroughIntermediateDirectoryStrategy(element, parserContext);
+ if (intermediateDirectoryStrategy != null) {
+ sourceManagerBuilder.addConstructorArgValue(intermediateDirectoryStrategy);
+ }
+ } else {
+ if (element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentNumber")
+ || element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentLength")) {
+ log.warn("{} Non-default source key manger in use, sourceDirectoryIntermediateSegmentNumber and "
+ + "sourceDirectoryIntermediateSegmentLength will be ignored. "
+ + "Use sourceDirectoryIntermediateStrategyRef instead");
+ }
+ }
+ }
+
+ /**
+ * Return bean definition for the default intermediate directory strategy with passthrough source strategy,
+ * if segmenting configuration params specified.
+ *
+ * @param element the element being parsed
+ * @param parserContext the current parser context
+ * @return the strategy bean definition, or null if not configured
+ */
+ private BeanDefinition checkAndBuildPassthroughIntermediateDirectoryStrategy(final Element element,
+ final ParserContext parserContext) {
+
+ if (!element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentNumber")
+ && !element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentLength") ) {
+ return null;
+ }
+
+ // Must have both params
+ if (!element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentNumber")
+ || !element.hasAttributeNS(null, "sourceDirectoryIntermediateSegmentLength")) {
+
+ log.error("{} LocalDynamicMetadataProvider contained either sourceDirectoryIntermediateSegmentNumber "
+ + "or sourceDirectoryIntermediateSegmentLength without the other",
+ parserContext.getReaderContext().getResource().getDescription());
+ throw new BeanDefinitionParsingException(
+ new Problem("Either sourceDirectoryIntermediateSegmentNumber or "
+ + "sourceDirectoryIntermediateSegmentLength was supplied without the other",
+ new Location( parserContext.getReaderContext().getResource())));
+ }
+
+ final BeanDefinitionBuilder strategyBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(SegmentingIntermediateDirectoryStrategy.class);
+ strategyBuilder.addConstructorArgValue(StringSupport.trimOrNull(
+ element.getAttributeNS(null, "sourceDirectoryIntermediateSegmentNumber")));
+ strategyBuilder.addConstructorArgValue(StringSupport.trimOrNull(
+ element.getAttributeNS(null, "sourceDirectoryIntermediateSegmentLength")));
+ strategyBuilder.addConstructorArgValue(new PassthroughSourceStrategy());
+ return strategyBuilder.getBeanDefinition();
+ }
+
}
diff --git a/idp-profile-spring/src/test/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/LocalDynamicMetadataProviderParserTest.java b/idp-profile-spring/src/test/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/LocalDynamicMetadataProviderParserTest.java
index bb81c4c7c..67c041726 100644
--- a/idp-profile-spring/src/test/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/LocalDynamicMetadataProviderParserTest.java
+++ b/idp-profile-spring/src/test/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/LocalDynamicMetadataProviderParserTest.java
@@ -19,7 +19,11 @@ package net.shibboleth.idp.profile.spring.relyingparty.metadata;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.time.Duration;
+import java.util.Comparator;
import java.util.concurrent.TimeUnit;
import org.opensaml.core.criterion.EntityIdCriterion;
@@ -30,6 +34,7 @@ import org.opensaml.saml.metadata.resolver.impl.AbstractDynamicMetadataResolver;
import org.opensaml.saml.metadata.resolver.impl.LocalDynamicMetadataResolver;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.security.crypto.JCAConstants;
+import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
@@ -53,18 +58,14 @@ public class LocalDynamicMetadataProviderParserTest extends AbstractMetadataPars
private final int TIME_GRANULARITY_MS = 25; // Dither for Windows clocks
@BeforeMethod
- public void setUp() {
+ public void setUp() throws IOException {
sourceDirectory = new File(System.getProperty("java.io.tmpdir"), "localDynamicMD");
+ resetSourceDirectory();
}
@AfterMethod
- public void tearDown() {
- if (sourceDirectory.exists()) {
- for (File child : sourceDirectory.listFiles()) {
- child.delete();
- }
- sourceDirectory.delete();
- }
+ public void tearDown() throws IOException {
+ resetSourceDirectory();
}
@Test
@@ -176,5 +177,122 @@ public class LocalDynamicMetadataProviderParserTest extends AbstractMetadataPars
Assert.assertEquals(resolved.getEntityID(), entityID);
}
+ @Test
+ public void testSourceDirectoryWithIntermediateNumberAndLength() throws Exception {
+ // Test that can correctly resolve when sourceDirectory is supplied with intermediate dir segment number and length
+ // SHA-1 hashes to: 9339685fdddbf8e45faac94340a3260468aa65bd
+ String entityID = "urn:test:entity1";
+ EntityDescriptor entity = (EntityDescriptor) XMLObjectSupport.buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
+ entity.setEntityID(entityID);
+
+ if (!sourceDirectory.exists()) {
+ Assert.assertTrue(sourceDirectory.mkdirs());
+ }
+ StringDigester digester = new StringDigester(JCAConstants.DIGEST_SHA1, OutputFormat.HEX_LOWER);
+ String sourceKey = digester.apply(entityID) + ".xml";
+ // Using segment number=1 and length=2
+ File sourceFile = Path.of(sourceDirectory.getAbsolutePath(), "93", sourceKey).toFile();
+
+ // First clear anything from previous test, and sanity check the setup
+ if (sourceFile.exists()) {
+ sourceFile.delete();
+ Assert.assertFalse(sourceFile.exists());
+ }
+
+ LocalDynamicMetadataResolver resolver = getBean(LocalDynamicMetadataResolver.class,
+ "localDynamicWithSourceDirectoryAndIntermediateNumberAndLength.xml", "beans.xml");
+
+ CriteriaSet criteria = new CriteriaSet(new EntityIdCriterion(entityID));
+
+ Assert.assertNull(resolver.resolveSingle(criteria));
+
+ sourceFile.getParentFile().mkdirs();
+ XMLObjectSupport.marshallToOutputStream(entity, new FileOutputStream(sourceFile));
+ Assert.assertTrue(sourceFile.exists());
+
+ // Configured negative lookup cache should still be in effect
+ Assert.assertNull(resolver.resolveSingle(criteria));
+
+ // Sleep past the negative lookup cache expiration
+ Uninterruptibles.sleepUninterruptibly(resolver.getNegativeLookupCacheDuration().toMillis()+TIME_GRANULARITY_MS, TimeUnit.MILLISECONDS);
+
+ EntityDescriptor resolved = resolver.resolveSingle(criteria);
+ Assert.assertNotNull(resolved);
+ Assert.assertEquals(resolved.getEntityID(), entityID);
+ }
+
+ @Test
+ public void testSourceDirectoryWithIntermediateStrategyRef() throws Exception {
+ // Test that can correctly resolve when sourceDirectory is supplied with intermediate dir strategy ref
+ // SHA-1 hashes to: 9339685fdddbf8e45faac94340a3260468aa65bd
+ String entityID = "urn:test:entity1";
+ EntityDescriptor entity = (EntityDescriptor) XMLObjectSupport.buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
+ entity.setEntityID(entityID);
+
+ if (!sourceDirectory.exists()) {
+ Assert.assertTrue(sourceDirectory.mkdirs());
+ }
+ StringDigester digester = new StringDigester(JCAConstants.DIGEST_SHA1, OutputFormat.HEX_LOWER);
+ String sourceKey = digester.apply(entityID) + ".xml";
+ // Using segment number=2 and length=2
+ File sourceFile = Path.of(sourceDirectory.getAbsolutePath(), "93", "39", sourceKey).toFile();
+
+ // First clear anything from previous test, and sanity check the setup
+ if (sourceFile.exists()) {
+ sourceFile.delete();
+ Assert.assertFalse(sourceFile.exists());
+ }
+
+ LocalDynamicMetadataResolver resolver = getBean(LocalDynamicMetadataResolver.class,
+ "localDynamicWithSourceDirectoryAndIntermediateStrategyRef.xml", "beans.xml");
+
+ CriteriaSet criteria = new CriteriaSet(new EntityIdCriterion(entityID));
+
+ Assert.assertNull(resolver.resolveSingle(criteria));
+
+ sourceFile.getParentFile().mkdirs();
+ XMLObjectSupport.marshallToOutputStream(entity, new FileOutputStream(sourceFile));
+ Assert.assertTrue(sourceFile.exists());
+
+ // Configured negative lookup cache should still be in effect
+ Assert.assertNull(resolver.resolveSingle(criteria));
+
+ // Sleep past the negative lookup cache expiration
+ Uninterruptibles.sleepUninterruptibly(resolver.getNegativeLookupCacheDuration().toMillis()+TIME_GRANULARITY_MS, TimeUnit.MILLISECONDS);
+
+ EntityDescriptor resolved = resolver.resolveSingle(criteria);
+ Assert.assertNotNull(resolved);
+ Assert.assertEquals(resolved.getEntityID(), entityID);
+ }
+
+ @Test(expectedExceptions=BeanDefinitionParsingException.class)
+ public void testSourceDirectoryIntermediateNumberWithoutLength() throws Exception {
+ getBean(LocalDynamicMetadataResolver.class, "localDynamicWithSourceDirectoryAndIntermediateNumberWithoutLength.xml", "beans.xml");
+ }
+
+ @Test(expectedExceptions=BeanDefinitionParsingException.class)
+ public void testSourceDirectoryIntermediateLengthWithoutNumber() throws Exception {
+ getBean(LocalDynamicMetadataResolver.class, "localDynamicWithSourceDirectoryAndIntermediateLengthWithoutNumber.xml", "beans.xml");
+ }
+
+ @Test(expectedExceptions=BeanDefinitionParsingException.class)
+ public void testMissingSourceDirectoryAndSourceManager() throws Exception {
+ getBean(LocalDynamicMetadataResolver.class, "localDynamicMissingSourceManagerAndSourceDirectory.xml", "beans.xml");
+ }
+
+ // Helpers
+ private void resetSourceDirectory() throws IOException {
+ if (sourceDirectory.exists()) {
+ if (sourceDirectory.isDirectory()) {
+ Files.walk(sourceDirectory.toPath())
+ .sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ } else {
+ sourceDirectory.delete();
+ }
+ }
+ }
+
}
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/beans.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/beans.xml
index 2dff5dfeb..53c024208 100644
--- a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/beans.xml
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/beans.xml
@@ -94,4 +94,12 @@
<bean id="metadata.classpathRef" class="org.springframework.core.io.ClassPathResource" c:_0="/net/shibboleth/idp/profile/spring/relyingparty/metadata/entity.xml"/>
+ <bean id="metadata.IntermediateDirectoryStrategy" class="org.opensaml.core.xml.persist.impl.SegmentingIntermediateDirectoryStrategy" >
+ <constructor-arg value="2" />
+ <constructor-arg value="2" />
+ <constructor-arg>
+ <bean class="org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy" />
+ </constructor-arg>
+ </bean>
+
</beans>
\ No newline at end of file
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicMissingSourceManagerAndSourceDirectory.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicMissingSourceManagerAndSourceDirectory.xml
new file mode 100644
index 000000000..fa7f789c1
--- /dev/null
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicMissingSourceManagerAndSourceDirectory.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:metadata="urn:mace:shibboleth:2.0:metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+ urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd"
+
+ id="localDynamicWithSourceDirectory" xsi:type="metadata:LocalDynamicMetadataProvider"
+ negativeLookupCacheDuration="PT1S"
+ >
+
+</metadata:MetadataProvider>
+
\ No newline at end of file
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateLengthWithoutNumber.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateLengthWithoutNumber.xml
new file mode 100644
index 000000000..d27dfbb4d
--- /dev/null
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateLengthWithoutNumber.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:metadata="urn:mace:shibboleth:2.0:metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+ urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd"
+
+ id="localDynamicWithSourceDirectory" xsi:type="metadata:LocalDynamicMetadataProvider"
+ negativeLookupCacheDuration="PT1S"
+ sourceDirectory="#{systemProperties['java.io.tmpdir']}/localDynamicMD"
+ sourceDirectoryIntermediateSegmentLength="2"
+ >
+
+</metadata:MetadataProvider>
+
\ No newline at end of file
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberAndLength.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberAndLength.xml
new file mode 100644
index 000000000..c86e5dbe0
--- /dev/null
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberAndLength.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:metadata="urn:mace:shibboleth:2.0:metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+ urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd"
+
+ id="localDynamicWithSourceDirectory" xsi:type="metadata:LocalDynamicMetadataProvider"
+ negativeLookupCacheDuration="PT1S"
+ sourceDirectory="#{systemProperties['java.io.tmpdir']}/localDynamicMD"
+ sourceDirectoryIntermediateSegmentNumber="1"
+ sourceDirectoryIntermediateSegmentLength="2"
+ >
+
+</metadata:MetadataProvider>
+
\ No newline at end of file
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberWithoutLength.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberWithoutLength.xml
new file mode 100644
index 000000000..a685d7f1c
--- /dev/null
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateNumberWithoutLength.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:metadata="urn:mace:shibboleth:2.0:metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+ urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd"
+
+ id="localDynamicWithSourceDirectory" xsi:type="metadata:LocalDynamicMetadataProvider"
+ negativeLookupCacheDuration="PT1S"
+ sourceDirectory="#{systemProperties['java.io.tmpdir']}/localDynamicMD"
+ sourceDirectoryIntermediateSegmentNumber="1"
+ >
+
+</metadata:MetadataProvider>
+
\ No newline at end of file
diff --git a/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateStrategyRef.xml b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateStrategyRef.xml
new file mode 100644
index 000000000..d1b2bb407
--- /dev/null
+++ b/idp-profile-spring/src/test/resources/net/shibboleth/idp/profile/spring/relyingparty/metadata/localDynamicWithSourceDirectoryAndIntermediateStrategyRef.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata:MetadataProvider xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:metadata="urn:mace:shibboleth:2.0:metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:metadata http://shibboleth.net/schema/idp/shibboleth-metadata.xsd
+ urn:oasis:names:tc:SAML:2.0:metadata http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd"
+
+ id="localDynamicWithSourceDirectory" xsi:type="metadata:LocalDynamicMetadataProvider"
+ negativeLookupCacheDuration="PT1S"
+ sourceDirectory="#{systemProperties['java.io.tmpdir']}/localDynamicMD"
+ sourceDirectoryIntermediateStrategyRef="metadata.IntermediateDirectoryStrategy"
+ >
+
+</metadata:MetadataProvider>
+
\ No newline at end of file
diff --git a/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd b/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
index d6cf9917f..679ec8cd6 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-metadata.xsd
@@ -515,6 +515,65 @@
</documentation>
</annotation>
</attribute>
+ <attribute name="sourceDirectoryIntermediateSegmentNumber" type="shibmd:string">
+ <annotation>
+ <documentation>
+ Convenience mechanism for specifying the number of intermediate directory segments
+ underneath the 'sourceDirectory', when a hashed directory approach is desired.
+ If this is supplied, then 'sourceDirectoryIntermediateSegmentLength' MUST also be supplied.
+
+ This attribute will be ignored if 'sourceManagerRef' is also specified.
+
+ This attribute will be ignored if 'sourceDirectoryIntermediateStrategyRef' is also specified.
+
+ This attribute will be ignored if 'sourceKeyGeneratorRef' is also specified. In that case
+ if an intermediate directory strategy is desired, 'sourceDirectoryIntermediateStrategyRef'
+ should be supplied instead.
+
+ Example: When segment number = 2, and segment length = 2, the metadata for the entity with
+ entityID "urn:test:foobar" in file "d278c9975472a6b4827b1a8723192b4e99aa969c.xml"
+ will be resolved from:
+
+ {sourceDirectory}/d2/78/d278c9975472a6b4827b1a8723192b4e99aa969c.xml
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="sourceDirectoryIntermediateSegmentLength" type="shibmd:string">
+ <annotation>
+ <documentation>
+ Convenience mechanism for specifying the number of intermediate directory segments
+ underneath the 'sourceDirectory', when a hashed directory approach is desired.
+ If this is supplied, then 'sourceDirectoryIntermediateSegmentNumber' MUST also be supplied.
+
+ This attribute will be ignored if 'sourceManagerRef' is also specified.
+
+ This attribute will be ignored if 'sourceDirectoryIntermediateStrategyRef' is also specified.
+
+ This attribute will be ignored if 'sourceKeyGeneratorRef' is also specified. In that case
+ if an intermediate directory strategy is desired, 'sourceDirectoryIntermediateStrategyRef'
+ should be supplied instead.
+
+ Example: When segment number = 2, and segment length = 2, the metadata for the entity with
+ entityID "urn:test:foobar" in file "d278c9975472a6b4827b1a8723192b4e99aa969c.xml"
+ will be resolved from:
+
+ {sourceDirectory}/d2/78/d278c9975472a6b4827b1a8723192b4e99aa969c.xml
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="sourceDirectoryIntermediateStrategyRef" type="shibmd:string">
+ <annotation>
+ <documentation>
+ Bean reference to the strategy for computing intermediate directories underneath the
+ 'sourceDirectory'.
+
+ This attribute overrides 'sourceDirectoryIntermediateSegmentNumber' and
+ 'sourceDirectoryIntermediateSegmentLength'.
+
+ This attribute will be ignored if 'sourceManagerRef' is also specified.
+ </documentation>
+ </annotation>
+ </attribute>
</extension>
</complexContent>
</complexType>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list