[java-oidfed-common] branch main updated: Add property to control maximum amount of authority hints to be locally resolved
Codeberg
noreply at shibboleth.net
Fri Sep 18 07:40:15 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-oidfed-common.
View the commit online:
https://codeberg.org/Shibboleth/java-oidfed-common/commit/fef3693f9b6cf8ed5897e87145e4a80fac24ae8d
The following commit(s) were added to refs/heads/main by this push:
new fef3693 Add property to control maximum amount of authority hints to be locally resolved
fef3693 is described below
commit fef3693f9b6cf8ed5897e87145e4a80fac24ae8d
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Sep 18 10:39:57 2026 +0300
Add property to control maximum amount of authority hints to be locally resolved
- idp.oidfed.cache.trustChain.maximumAuthorityHints, defaults to 5
- If the limit is exceeded in entity configuration, the respective trust chain is ignored
---
.../META-INF/net.shibboleth.idp/postconfig.xml | 7 ++++
.../DefaultTrustChainFetchingStrategy.java | 38 +++++++++++++++++--
.../oidfed/conf/oidfed/oidfed.properties | 4 ++
.../DefaultTrustChainFetchingStrategyTest.java | 44 ++++++++++++++++++++++
4 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index f22ca63..d0e5188 100644
--- a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -412,6 +412,13 @@
</constructor-arg>
</bean>
</property>
+ <property name="criteriaToMaximumAuthorityHintsStrategy">
+ <bean parent="shibboleth.Functions.Constant">
+ <constructor-arg>
+ <bean class="java.lang.Integer" factory-method="parseInt" c:_0="%{idp.oidfed.cache.trustChain.maximumAuthorityHints:5}" />
+ </constructor-arg>
+ </bean>
+ </property>
</bean>
</property>
</bean>
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategy.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategy.java
index bf2b825..5d19f09 100644
--- a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategy.java
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategy.java
@@ -84,6 +84,9 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
/** Strategy to fetch maximum length for trust chains. */
@NonnullAfterInit private Function<CriteriaSet, Integer> criteriaToMaximumChainLengthStrategy;
+ /** Strategy to fetch maximum amount of authority hints to be processed. */
+ @NonnullAfterInit private Function<CriteriaSet, Integer> criteriaToMaximumAuthorityHintsStrategy;
+
/**
* Set the strategy for fetching entity ID from the criteria set.
*
@@ -160,6 +163,17 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
Constraint.isNotNull(strategy, "Criteria to maximum trust chain length strategy cannot be null");
}
+ /**
+ * Set the strategy to fetch maximum amount of authority hints to be processed.
+ *
+ * @param strategy maximum authority hints strategy
+ */
+ public void setCriteriaToMaximumAuthorityHintsStrategy(@Nonnull final Function<CriteriaSet, Integer> strategy) {
+ checkSetterPreconditions();
+ criteriaToMaximumAuthorityHintsStrategy =
+ Constraint.isNotNull(strategy, "Criteria to maximum authority hints strategy cannot be null");
+ }
+
/** {@inheritDoc} */
@Override
protected void doInitialize() throws ComponentInitializationException {
@@ -187,6 +201,10 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
throw new ComponentInitializationException(
"Criteria to maximum trust chain length strategy cannot be null");
}
+ if (criteriaToMaximumAuthorityHintsStrategy == null) {
+ throw new ComponentInitializationException(
+ "Criteria to maximum authority hints strategy cannot be null");
+ }
}
/** {@inheritDoc} */
@@ -233,6 +251,12 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
log.warn("Could not fetch valid maximum trust chain length, it must be greater than 2: {}", maximumLength);
return null;
}
+ final Integer maximumAuthorityHints = criteriaToMaximumAuthorityHintsStrategy.apply(criteria);
+ if (maximumAuthorityHints == null || maximumLength.intValue() < 1) {
+ log.warn("Could not fetch valid maximum authority hints, it must be greater than 0: {}", maximumLength);
+ return null;
+ }
+
log.trace("Entity configuration found to build the trust chains on: {}", entityConfiguration != null);
if (entityConfiguration == null) {
return null;
@@ -246,7 +270,8 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
return null;
}
final List<TrustChainWrapper> populatedWrappers = populateChain(
- CollectionSupport.listOf(initialWrapper), preSelectedChain, maximumLength.intValue());
+ CollectionSupport.listOf(initialWrapper), preSelectedChain, maximumLength.intValue(),
+ maximumAuthorityHints.intValue());
final List<List<EntityStatement<?>>> result = populatedWrappers.stream()
.filter(wrapper -> wrapper.isComplete())
.map(wrapper -> wrapper.getTrustChain())
@@ -288,11 +313,12 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
* @param entities the list of trust chains being populated.
* @param preSelectedChain the pre-selected trust chain (containing entity IDs as String).
* @param maxChainLength the maximum length of trust chain, longer than this limit will be ignored
+ * @param maxAuthorityHints the maximum amount of authority hints
* @return the list of trust chains being populated
*/
@Nonnull @NonnullElements private List<TrustChainWrapper> populateChain(
@Nonnull @NonnullElements final List<TrustChainWrapper> entities,
- @Nonnull final List<String> preSelectedChain, final int maxChainLength) {
+ @Nonnull final List<String> preSelectedChain, final int maxChainLength, final int maxAuthorityHints) {
final List<TrustChainWrapper> result = new ArrayList<>();
boolean hints = false;
for (final TrustChainWrapper chainWrapper : entities) {
@@ -315,6 +341,12 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
+ ", leaf {}", authorityHints, entityStatement.getSubject(), chain.get(0).getSubject());
continue;
}
+ if (authorityHints.size() > maxAuthorityHints) {
+ log.info("Maximum authority hints limit ({}) has been met, ignoring authority hints {} of {}",
+ maxAuthorityHints, authorityHints, entityStatement.getSubject());
+ continue;
+ }
+
final List<Pair<EntityConfiguration, SubordinateStatement>> authorities = authorityHints.stream()
.filter(id -> verifyNoLoop(chain, id))
.filter(id -> verifyPreSelected(chain, id, preSelectedChain))
@@ -333,7 +365,7 @@ public class DefaultTrustChainFetchingStrategy extends AbstractIdentifiableIniti
}
}
if (hints) {
- return populateChain(result, preSelectedChain, maxChainLength);
+ return populateChain(result, preSelectedChain, maxChainLength, maxAuthorityHints);
}
return result;
}
diff --git a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/conf/oidfed/oidfed.properties b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/conf/oidfed/oidfed.properties
index 53beafa..bf994d4 100644
--- a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/conf/oidfed/oidfed.properties
+++ b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/conf/oidfed/oidfed.properties
@@ -60,6 +60,10 @@ idp.oidfed.entityConfiguration.authorityHints = https://your.authority.example.o
# - trust anchor and intermediate: 4 (leaf configuration, subordinate statements about leaf and intermediate, anchor configuration)
#idp.oidfed.cache.trustChain.maximumChainLength = 5
+# Maximum amount of authority_hints
+# if any entity configuration exceeds the limit, the respective trust chain is ignored
+#idp.oidfed.cache.trustChain.maximumAuthorityHints = 5
+
#idp.oidfed.cache.trustChain.cleanupTaskInterval = PT5M
#idp.oidfed.cache.trustChain.customFilterStrategies =
#idp.oidfed.cache.trustChain.validContainerLifetime = PT5M
diff --git a/oidfed-common-impl/src/test/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategyTest.java b/oidfed-common-impl/src/test/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategyTest.java
index cf57464..c4fe387 100644
--- a/oidfed-common-impl/src/test/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategyTest.java
+++ b/oidfed-common-impl/src/test/java/net/shibboleth/oidfed/metadata/cache/trustchain/DefaultTrustChainFetchingStrategyTest.java
@@ -58,6 +58,7 @@ public class DefaultTrustChainFetchingStrategyTest {
Function<CriteriaSet, Duration> criteriaToValidContainerLifetimeStrategy;
Function<CriteriaSet, Duration> criteriaToInvalidContainerLifetimeStrategy;
Function<CriteriaSet, Integer> criteriaToMaximumChainLengthStrategy;
+ Function<CriteriaSet, Integer> criteriaToMaximumAuthorityHintsStrategy;
@SuppressWarnings("unchecked")
public void initMocks() {
@@ -68,6 +69,7 @@ public class DefaultTrustChainFetchingStrategyTest {
criteriaToValidContainerLifetimeStrategy = mock(Function.class);
criteriaToInvalidContainerLifetimeStrategy = mock(Function.class);
criteriaToMaximumChainLengthStrategy = mock(Function.class);
+ criteriaToMaximumAuthorityHintsStrategy = mock(Function.class);
}
@BeforeMethod
@@ -81,6 +83,7 @@ public class DefaultTrustChainFetchingStrategyTest {
function.setCriteriaToValidContainerLifetimeStrategy(criteriaToValidContainerLifetimeStrategy);
function.setCriteriaToInvalidContainerLifetimeStrategy(criteriaToInvalidContainerLifetimeStrategy);
function.setCriteriaToMaximumChainLengthStrategy(criteriaToMaximumChainLengthStrategy);
+ function.setCriteriaToMaximumAuthorityHintsStrategy(criteriaToMaximumAuthorityHintsStrategy);
function.setId("mockFunction");
try {
function.initialize();
@@ -99,6 +102,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(null);
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
Assert.assertEquals(function.apply(new CriteriaSet()), null);
}
@@ -107,6 +111,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(null);
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
Assert.assertEquals(function.apply(new CriteriaSet()), null);
}
@@ -116,6 +121,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
when(entityConfigurationCache.get(any())).thenReturn(CollectionSupport.emptyList());
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
Assert.assertEquals(function.apply(new CriteriaSet()), null);
}
@@ -125,6 +131,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
when(entityConfigurationCache.get(any())).thenThrow(MetadataCacheException.class);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
Assert.assertEquals(function.apply(new CriteriaSet()), null);
}
@@ -133,6 +140,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer("mockEntityId", CollectionSupport.emptyList());
when(entityConfigurationCache.get(any())).thenReturn(CollectionSupport.listOf(ecContainer));
@@ -144,6 +152,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer("mockEntityId", CollectionSupport.listOf("https://federation.local/immediate"));
when(entityConfigurationCache.get(any())).thenReturn(CollectionSupport.listOf(ecContainer));
@@ -158,6 +167,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(anchor, "https://federation.local/other"));
final EntityConfigurationContainer authorityContainer =
@@ -186,6 +196,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(immediate, "https://federation.local/other"));
final EntityConfigurationContainer immediateContainer =
@@ -216,6 +227,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(immediate));
final EntityConfigurationContainer immediateContainer =
@@ -252,6 +264,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(3);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(immediate));
final EntityConfigurationContainer immediateContainer =
@@ -287,6 +300,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(anchor, "https://federation.local/other"));
final EntityConfigurationContainer authorityContainer =
@@ -316,6 +330,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(anchor, "https://federation.local/other"));
final EntityConfigurationContainer authorityContainer =
@@ -338,6 +353,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(2);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(anchor1, anchor2));
final EntityConfigurationContainer authorityContainer1 =
@@ -361,6 +377,33 @@ public class DefaultTrustChainFetchingStrategyTest {
List.of(leaf, anchor2));
}
+ @SuppressWarnings("unchecked")
+ @Test
+ public void entityConfigurationTwoResolvableHints_limitToOne_returnsEmotyContainer()
+ throws MetadataCacheException {
+ final String leaf = "https://federation.local/leaf";
+ final String anchor1 = "https://federation.local/immediate1";
+ final String anchor2 = "https://federation.local/immediate2";
+ when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
+ when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
+ when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
+ final EntityConfigurationContainer ecContainer =
+ ecContainer(leaf, CollectionSupport.listOf(anchor1, anchor2));
+ final EntityConfigurationContainer authorityContainer1 =
+ ecContainer(anchor1, CollectionSupport.emptyList());
+ final EntityConfigurationContainer authorityContainer2 =
+ ecContainer(anchor2, CollectionSupport.emptyList());
+ when(entityConfigurationCache.get(any()))
+ .thenReturn(CollectionSupport.listOf(ecContainer), CollectionSupport.listOf(authorityContainer1),
+ CollectionSupport.listOf(authorityContainer2));
+ final SubordinateStatementContainer ssContainer1 = ssContainer(leaf, anchor1);
+ final SubordinateStatementContainer ssContainer2 = ssContainer(leaf, anchor2);
+ when(subordinateStatementCache.get(any())).thenReturn(CollectionSupport.listOf(ssContainer1),
+ CollectionSupport.listOf(ssContainer2));
+ assertEmptyResult(function.apply(new CriteriaSet()));
+ }
+
@SuppressWarnings("unchecked")
@Test
public void entityConfigurationAuthorityLoop_returnsEmptyContantainer() throws MetadataCacheException {
@@ -370,6 +413,7 @@ public class DefaultTrustChainFetchingStrategyTest {
when(criteriaToValidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToInvalidContainerLifetimeStrategy.apply(any())).thenReturn(Duration.ofMinutes(5));
when(criteriaToMaximumChainLengthStrategy.apply(any())).thenReturn(4);
+ when(criteriaToMaximumAuthorityHintsStrategy.apply(any())).thenReturn(1);
final EntityConfigurationContainer ecContainer =
ecContainer(leaf, CollectionSupport.listOf(anchor1));
final EntityConfigurationContainer authorityContainer1 =
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list