[java-idp-plugin-oidc-op-oidfed] branch main updated: Refactored the configuration of trusted remote resolver entities.
Henri Mikkonen
henri.mikkonen at iki.fi
Tue Oct 21 14:28:29 UTC 2025
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-plugin-oidc-op-oidfed.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-op-oidfed.git;a=commit;h=bb151ebfb64538dcaf5d280930d54e5220891334
The following commit(s) were added to refs/heads/main by this push:
new bb151eb Refactored the configuration of trusted remote resolver entities.
bb151eb is described below
commit bb151ebfb64538dcaf5d280930d54e5220891334
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Oct 21 17:27:36 2025 +0300
Refactored the configuration of trusted remote resolver entities.
- Renamed 'shibboleth.oidfed.DefaultTrustedEntitiesLookupStrategy' into 'shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy'
- May be overridden via 'shibboleth.oidfed.TrustedRemoteResolverEntitiesLookupStrategy'
- The implementing function is expected to return List<TrustedRemoteResolverEntity> instead of the Map
- Example bean in the list: <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity" c:entity="https://trust-anchor.federation.local" c:anchors="https://trust-anchor.federation.local" />
- Multiple anchors may be fed by separating the values with commas
---
.../profile/TrustedRemoteResolverEntity.java | 65 ++++++++++++++++++++++
.../oidfed/profile/impl/CallResolveEntityApi.java | 36 ++++++------
.../oidfed/metadata-lookup-ext-oidfed-beans.xml | 2 +-
.../idp/flows/oidfed/register/register-beans.xml | 2 +-
.../conf/oidfed/oidfed-trustchain-resolver.xml | 20 +++----
.../conf/oidfed/oidfed-trustchain-resolver.xml | 17 +++---
6 files changed, 105 insertions(+), 37 deletions(-)
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/TrustedRemoteResolverEntity.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/TrustedRemoteResolverEntity.java
new file mode 100644
index 0000000..b8b6859
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/TrustedRemoteResolverEntity.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.oidfed.profile;
+
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * A trusted entity whose federation_resolve_endpoint is exploited.
+ */
+public class TrustedRemoteResolverEntity {
+
+ /** The entity ID of the remote resolver. */
+ @Nonnull @NotEmpty private final String entityId;
+
+ /** The trust anchors to be used within the API request. */
+ @Nonnull @NotEmpty private final Collection<String> trustAnchors;
+
+ /**
+ * Constructor.
+ *
+ * @param entity ntity ID of the remote resolver
+ * @param anchors trust anchors to be used within the API request
+ */
+ public TrustedRemoteResolverEntity(@Nonnull @NotEmpty @ParameterName(name="entity") final String entity,
+ @Nonnull @NotEmpty @ParameterName(name="anchors") final Collection<String> anchors) {
+ entityId = Constraint.isNotEmpty(entity, "Entity ID cannot be empty");
+ trustAnchors = Constraint.isNotEmpty(anchors, "Trust Anchors cannot be empty");
+ }
+
+ /**
+ * Get the entity ID of the remote resolver.
+ *
+ * @return entity ID of the remote resolver
+ */
+ @Nonnull @NotEmpty public String getEntityId() {
+ return entityId;
+ }
+
+ /**
+ * Get the trust anchors to be used within the API request.
+ *
+ * @return trust anchors to be used within the API request
+ */
+ @Nonnull @NotEmpty public Collection<String> getTrustAnchors() {
+ return trustAnchors;
+ }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
index 9533db0..127e727 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
@@ -53,6 +53,7 @@ import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponseCo
import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResponseContainerExpirationCriterion;
import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityIDCriterion;
import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityStatementCriterion;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultPreSelectedTrustChainIDsLookupStrategy;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultTrustChainIDsLookupStrategy;
import net.shibboleth.idp.profile.AbstractProfileAction;
@@ -110,7 +111,8 @@ public class CallResolveEntityApi extends AbstractProfileAction {
@Nonnull private Predicate<ProfileRequestContext> requireEntityConfigurationCondition;
/** Strategy used to get map of trusted entities for resolve entity APIs. */
- @NonnullAfterInit private Function<ProfileRequestContext, Map<String,List<String>>> trustedEntitiesLookupStrategy;
+ @NonnullAfterInit
+ private Function<ProfileRequestContext, List<TrustedRemoteResolverEntity>> trustedEntitiesLookupStrategy;
/** Strategy used to fetch the entity types used in the resolve entity request. */
@Nonnull private Function<ProfileRequestContext, List<String>> entityTypesLookupStrategy;
@@ -125,7 +127,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
@NonnullBeforeExec private String clientId;
/** Trusted entities to use. */
- @NonnullBeforeExec private Map<String,List<String>> trustedEntities;
+ @NonnullBeforeExec private List<TrustedRemoteResolverEntity> trustedEntities;
/**
* Constructor.
@@ -234,7 +236,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
* @param strategy lookup strategy
*/
public void setTrustedEntitiesLookupStrategy(
- @Nonnull final Function<ProfileRequestContext,Map<String,List<String>>> strategy) {
+ @Nonnull final Function<ProfileRequestContext, List<TrustedRemoteResolverEntity>> strategy) {
checkSetterPreconditions();
trustedEntitiesLookupStrategy = Constraint.isNotNull(strategy, "TrustedEntitiesLookupStrategy cannot be null");
}
@@ -327,11 +329,11 @@ public class CallResolveEntityApi extends AbstractProfileAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
log.debug("{} Resolving trust chain via resolve entity API for {}", getLogPrefix(), clientId);
assert clientId != null;
- final CriteriaSet criteriaSet = new CriteriaSet(new SubjectEntityIDCriterion(clientId));
+ final CriteriaSet baseCriteriaSet = new CriteriaSet(new SubjectEntityIDCriterion(clientId));
final EntityStatement entityConfiguration = entityConfigurationLookupStrategy.apply(profileRequestContext);
if (entityConfiguration != null) {
log.debug("{} Entity configuration resolved and included to the criteria set", getLogPrefix());
- criteriaSet.add(new SubjectEntityStatementCriterion(entityConfiguration));
+ baseCriteriaSet.add(new SubjectEntityStatementCriterion(entityConfiguration));
} else if (requireEntityConfigurationCondition.test(profileRequestContext)) {
log.error("{} Mandatory entity configuration could not be resolved", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
@@ -343,16 +345,15 @@ public class CallResolveEntityApi extends AbstractProfileAction {
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
return;
}
- criteriaSet.add(new ResponseContainerExpirationCriterion(Instant.now().plus(cachedLifetime)));
+ baseCriteriaSet.add(new ResponseContainerExpirationCriterion(Instant.now().plus(cachedLifetime)));
final List<String> preSelectedChain =
Optional.ofNullable(preSelectedTrustChainIdsLookupStrategy.apply(profileRequestContext))
.orElse(CollectionSupport.emptyList());
- for (final String trustedEntity : trustedEntities.keySet()) {
- final List<String> trustAnchors = trustedEntities.get(trustedEntity);
- if (trustAnchors == null || trustAnchors.isEmpty()) {
- log.warn("{} No trust anchors defined for trusted entity {}", getLogPrefix(), trustedEntity);
+ for (final TrustedRemoteResolverEntity trustedEntity : trustedEntities) {
+ if (trustedEntity == null) {
+ log.warn("{} Ignoring null trusted entity entry", getLogPrefix());
continue;
}
final URI uri = fetchResolveEntityEndpoint(trustedEntity);
@@ -361,7 +362,9 @@ public class CallResolveEntityApi extends AbstractProfileAction {
continue;
}
final ResolveEntityRequest entityRequest = new ResolveEntityRequest(
- uri, clientId, trustAnchors, List.of("openid_relying_party"));
+ uri, clientId, List.copyOf(trustedEntity.getTrustAnchors()), List.of("openid_relying_party"));
+ final CriteriaSet criteriaSet = new CriteriaSet();
+ baseCriteriaSet.forEach(c -> criteriaSet.add(c));
criteriaSet.add(new ResolveEntityRequestCriterion(entityRequest));
final List<ResolveEntityResponseContainer> cacheResult;
try {
@@ -470,10 +473,11 @@ public class CallResolveEntityApi extends AbstractProfileAction {
/**
* Fetch the resolve entity endpoint via entity configuration from the metadata cache.
*
- * @param subject the entity ID
+ * @param trustedEntity the trusted entity
* @return the resolve entity endpoint, or null if could not be fetched
*/
- @Nullable protected URI fetchResolveEntityEndpoint(@Nonnull final String subject) {
+ @Nullable protected URI fetchResolveEntityEndpoint(@Nonnull final TrustedRemoteResolverEntity trustedEntity) {
+ final String subject = trustedEntity.getEntityId();
final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(subject));
try {
final List<EntityStatement> result = entityConfigurationCache.get(criteria);
@@ -489,9 +493,9 @@ public class CallResolveEntityApi extends AbstractProfileAction {
.orElse(null);
}
} catch (final MetadataCacheException e) {
- log.debug("Error while fetching entity configuration for {}", subject, e);
+ log.debug("{} Error while fetching entity configuration for {}", getLogPrefix(), subject, e);
}
- log.warn("Could not fetch entity configuration for {}", subject);
+ log.warn("{} Could not fetch entity configuration for {}", getLogPrefix(), subject);
return null;
}
@@ -506,7 +510,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
try {
return SignedJWT.parse(string);
} catch (final ParseException e) {
- log.error("Could not parse the trust mark into a JWT", e);
+ log.error("{} Could not parse the trust mark into a JWT", getLogPrefix(), e);
}
}
return null;
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
index d8c2f11..1ebbf25 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
@@ -22,7 +22,7 @@
p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"
p:resolveEntityTrustChainMetadataCache-ref="shibboleth.oidfed.ResolveEntityTrustChainMetadataCache"
p:objectMapper-ref="shibboleth.oidc.JSONObjectMapper"
- p:trustedEntitiesLookupStrategy="#{getObject('shibboleth.oidfed.TrustedEntitiesLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultTrustedEntitiesLookupStrategy')}"
+ p:trustedEntitiesLookupStrategy="#{getObject('shibboleth.oidfed.TrustedRemoteResolverEntitiesLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy')}"
p:preSelectedTrustChainIdsLookupStrategy="#{getObject('shibboleth.oidfed.PreSelectedTrustChainIDsLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy')}">
<property name="clientIDLookupStrategy">
<bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultMetadataLookupExtensionContextClientIDLookupFunction" />
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
index 33283ad..23e4083 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
@@ -84,7 +84,7 @@
p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"
p:resolveEntityTrustChainMetadataCache-ref="shibboleth.oidfed.ResolveEntityTrustChainMetadataCache"
p:objectMapper-ref="shibboleth.oidc.JSONObjectMapper"
- p:trustedEntitiesLookupStrategy="#{getObject('shibboleth.oidfed.TrustedEntitiesLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultTrustedEntitiesLookupStrategy')}"
+ p:trustedEntitiesLookupStrategy="#{getObject('shibboleth.oidfed.TrustedRemoteResolverEntitiesLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy')}"
p:preSelectedTrustChainIdsLookupStrategy="#{getObject('shibboleth.oidfed.PreSelectedTrustChainIDsLookupStrategy') ?: getObject('shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy')}"
p:requireEntityConfigurationCondition-ref="shibboleth.Conditions.TRUE">
<property name="entityConfigurationLookupStrategy">
diff --git a/idp-oidfed-op-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/oidfed/conf/oidfed/oidfed-trustchain-resolver.xml b/idp-oidfed-op-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/oidfed/conf/oidfed/oidfed-trustchain-resolver.xml
index 8a26100..11a1387 100644
--- a/idp-oidfed-op-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/oidfed/conf/oidfed/oidfed-trustchain-resolver.xml
+++ b/idp-oidfed-op-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/oidfed/conf/oidfed/oidfed-trustchain-resolver.xml
@@ -15,25 +15,23 @@
The entity configuration is used as a trusted source for the endpoint. The map value is a list of trust anchors
that will be used for the trust_anchor paramter(s) in the API request.
- The default function may be overridden via 'shibboleth.oidfed.TrustedEntitiesLookupStrategy' bean that must
- implement Function<ProfileRequestContext, Map<String,List<String>>>.
+ The default function may be overridden via 'shibboleth.oidfed.TrustedRemoteResolverEntitiesLookupStrategy' bean
+ that must implement Function<ProfileRequestContext, List<TrustedRemoteResolverEntity>>.
-->
- <bean id="shibboleth.oidfed.DefaultTrustedEntitiesLookupStrategy" parent="shibboleth.Functions.Constant">
+ <bean id="shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy" parent="shibboleth.Functions.Constant">
<constructor-arg name="target">
- <util:map>
+ <util:list value-type="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity">
<!--
Example entry for a trusted entity 'https://trust-anchor.federation.local'
its 'federation_resolve_endpoint' is exploited with the configured trust_anchor parameters:
- '...&trust_anchor=https://trust-anchor.federation.local'
+ '...&trust_anchor=https://trust-anchor.federation.local&trust_anchor=https://another.federation.local'
-->
<!--
- <entry key="https://trust-anchor.federation.local">
- <util:list value-type="java.lang.String">
- <value>https://trust-anchor.federation.local</value>
- </util:list>
- </entry>
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity"
+ c:entity="https://trust-anchor.federation.local"
+ c:anchors="https://trust-anchor.federation.local,https://another.federation.local" />
-->
- </util:map>
+ </util:list>
</constructor-arg>
</bean>
diff --git a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/oidfed/oidfed-trustchain-resolver.xml b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/oidfed/oidfed-trustchain-resolver.xml
index e831bef..82f7d6b 100644
--- a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/oidfed/oidfed-trustchain-resolver.xml
+++ b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/oidfed/oidfed-trustchain-resolver.xml
@@ -9,15 +9,16 @@
default-init-method="initialize" default-destroy-method="destroy">
- <bean id="shibboleth.oidfed.DefaultTrustedEntitiesLookupStrategy" parent="shibboleth.Functions.Constant">
+ <bean id="shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy" parent="shibboleth.Functions.Constant">
<constructor-arg name="target">
- <util:map>
- <entry key="https://trust-anchor.federation.local">
- <util:list value-type="java.lang.String">
- <value>https://trust-anchor.federation.local</value>
- </util:list>
- </entry>
- </util:map>
+ <util:list value-type="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity"
+ c:entity="https://trust-anchor.federation.local"
+ c:anchors="https://notworking.local,https://neither.another.local" />
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity"
+ c:entity="https://trust-anchor.federation.local"
+ c:anchors="https://trust-anchor.federation.local" />
+ </util:list>
</constructor-arg>
</bean>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list