[java-idp-plugin-oidc-op-oidfed] branch main updated: Improvements to trust mark handling
Codeberg
noreply at shibboleth.net
Mon Oct 5 13:56:55 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-idp-plugin-oidc-op-oidfed.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-oidc-op-oidfed/commit/7c3ee1c3531aca89a11474867ee4d2a254022fb4
The following commit(s) were added to refs/heads/main by this push:
new 7c3ee1c Improvements to trust mark handling
7c3ee1c is described below
commit 7c3ee1c3531aca89a11474867ee4d2a254022fb4
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Mon Oct 5 16:56:29 2026 +0300
Improvements to trust mark handling
- Store expiration time of trust marks into the client information extensions
- Split ValidateAutomaticRegistrationProfileConfiguration into ValidateFederationRegistrationProfileConfiguration for serving explicit registration better
- Modify trust mark attribute filter to also server sxplicit registration (client information extensions)
- Cover in tests
---
.../policyrule/impl/EntityTrustMarkPolicyRule.java | 112 +++++++--
.../impl/EntityTrustMarkPolicyRuleParser.java | 16 ++
.../impl/AddExtensionsToClientInformation.java | 53 ++++-
...eAutomaticRegistrationProfileConfiguration.java | 262 ++++-----------------
...ederationRegistrationProfileConfiguration.java} | 107 ++-------
.../oidfed/metadata-lookup-ext-oidfed-beans.xml | 4 +
.../idp/flows/oidfed/register/register-beans.xml | 2 +-
.../resources/schema/shibboleth-afp-oidfed.xsd | 10 +-
.../UserInfoFlowAutomaticRegistrationTest.java | 65 +++++
.../idp/module/conf/attribute-filter.xml | 2 +-
10 files changed, 306 insertions(+), 327 deletions(-)
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/policyrule/impl/EntityTrustMarkPolicyRule.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/policyrule/impl/EntityTrustMarkPolicyRule.java
index 8635ddc..ad17442 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/policyrule/impl/EntityTrustMarkPolicyRule.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/policyrule/impl/EntityTrustMarkPolicyRule.java
@@ -14,6 +14,9 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.attribute.filter.policyrule.impl;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -26,9 +29,15 @@ import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
import org.slf4j.Logger;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
import net.shibboleth.idp.attribute.filter.PolicyRequirementRule;
import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext;
+import net.shibboleth.oidfed.support.ClientInformationExtensionSupport;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -48,9 +57,15 @@ public class EntityTrustMarkPolicyRule extends AbstractIdentifiableInitializable
/** String to match for a positive evaluation. */
@Nullable private String matchString;
+ /** Whether the match evaluation is case sensitive. */
+ private boolean caseSensitive = true;
+
/** The String used to prefix log message. */
@Nullable private String logPrefix;
+ /** Positive clock skew adjustment to consider when checking trust mark expiration. */
+ @Nonnull private Duration clockSkew;
+
/**
* Constructor.
*/
@@ -61,6 +76,9 @@ public class EntityTrustMarkPolicyRule extends AbstractIdentifiableInitializable
assert tcls != null;
trustChainContextLookupStrategy = tcls;
logPrefix = null;
+ final Duration sixtySeconds = Duration.ofSeconds(60);
+ assert sixtySeconds != null;
+ clockSkew = sixtySeconds;
}
/**
@@ -85,6 +103,27 @@ public class EntityTrustMarkPolicyRule extends AbstractIdentifiableInitializable
matchString = match;
}
+ /**
+ * Sets whether the policy evaluation is case sensitive.
+ *
+ * @param isCaseSensitive whether the policy evaluation is case sensitive
+ */
+ public void setCaseSensitive(final boolean isCaseSensitive) {
+ checkSetterPreconditions();
+ caseSensitive = isCaseSensitive;
+ }
+
+ /**
+ * Set the clock skew.
+ *
+ * @param skew clock skew to set
+ */
+ public void setClockSkew(@Nonnull final Duration skew) {
+ checkSetterPreconditions();
+ clockSkew = Constraint.isNotNull(skew, "Clock skew cannot be null");
+ Constraint.isFalse(clockSkew.isNegative(), "Clock skew cannot be negative");
+ }
+
/**
* Return a string which is to be prepended to all log messages.
*
@@ -114,26 +153,69 @@ public class EntityTrustMarkPolicyRule extends AbstractIdentifiableInitializable
@Override
public Tristate matches(@Nonnull final AttributeFilterContext filterContext) {
checkComponentActive();
- final RelyingPartyTrustChainContext trustChainContext = trustChainContextLookupStrategy.apply(
- new RecursiveTypedParentContextLookup<>(ProfileRequestContext.class).apply(filterContext));
- if (trustChainContext == null) {
- log.debug("{} No RelyingPartyTrustChainContext resolved", getLogPrefix());
- return Tristate.FALSE;
+ final ProfileRequestContext profileRequestContext =
+ new RecursiveTypedParentContextLookup<>(ProfileRequestContext.class).apply(filterContext);
+ final RelyingPartyTrustChainContext trustChainContext =
+ trustChainContextLookupStrategy.apply(profileRequestContext);
+ if (trustChainContext != null) {
+ final String entityId = Optional.ofNullable(trustChainContext.getSelectedTrustChain())
+ .map(verifiedChain -> verifiedChain.getTrustChain())
+ .map(chain -> chain.get(0))
+ .map(statement -> statement.getSubject())
+ .orElse(null);
+ if (entityId == null) {
+ log.debug("{} Could not resolve entity ID from selected trust chain", getLogPrefix());
+ return Tristate.FALSE;
+ }
+ final Boolean result = Optional.ofNullable(trustChainContext.getVerifiedTrustMarkIds())
+ .map(map -> map.get(entityId))
+ .map(ids -> listContains(ids, matchString))
+ .orElse(Boolean.FALSE);
+ log.debug("{} Returning {}", getLogPrefix(), result);
+ return result.booleanValue() ? Tristate.TRUE : Tristate.FALSE;
}
- final String entityId = Optional.ofNullable(trustChainContext.getSelectedTrustChain())
- .map(verifiedChain -> verifiedChain.getTrustChain())
- .map(chain -> chain.get(0))
- .map(statement -> statement.getSubject())
+
+ final OIDCClientInformation clientInformation = Optional.ofNullable(profileRequestContext)
+ .map(prc -> prc.getInboundMessageContext())
+ .map(msgCtx -> msgCtx.getSubcontext(OIDCMetadataContext.class))
+ .map(oidcCtx -> oidcCtx.getClientInformation())
.orElse(null);
- if (entityId == null) {
- log.debug("{} Could not resolve entity ID from selected trust chain", getLogPrefix());
+ if (clientInformation == null) {
+ log.debug("{} Could not resolve client information or RelyingPartyTrustChainContext, unable to proceed",
+ getLogPrefix());
return Tristate.FALSE;
}
- final Boolean result = Optional.ofNullable(trustChainContext.getVerifiedTrustMarkIds())
+
+ final String entityId = clientInformation.getID().getValue();
+ final List<Pair<String,Instant>> trustMarkIds =
+ Optional.ofNullable(ClientInformationExtensionSupport.parseValidatedTrustMarkIds(clientInformation))
.map(map -> map.get(entityId))
- .map(ids -> ids.contains(matchString))
- .orElse(Boolean.FALSE);
+ .orElse(CollectionSupport.emptyList());
+ log.debug("{} Resolved trust mark IDs via client information {}", getLogPrefix(), trustMarkIds);
+ final Instant expiration = Instant.now().minus(clockSkew);
+ final boolean result = listContains(trustMarkIds.stream()
+ .filter(pair -> pair.getSecond() == null || expiration.isBefore(pair.getSecond()))
+ .map(pair -> pair.getFirst()).toList(), matchString);
log.debug("{} Returning {}", getLogPrefix(), result);
- return result.booleanValue() ? Tristate.TRUE : Tristate.FALSE;
+ return result ? Tristate.TRUE : Tristate.FALSE;
+ }
+
+ /**
+ * Checks whether the given list contains the string to match, taking {@link #caseSensitive} into account.
+ *
+ * @param list the list to iterate over
+ * @param matchString the string to match
+ * @return true if the list contains the string, false otherwise
+ */
+ protected boolean listContains(@Nullable final List<String> list, @Nullable final String matchString) {
+ if (list == null || matchString == null) {
+ return false;
+ }
+ for (final String item : list) {
+ if (caseSensitive ? matchString.equals(item) : matchString.equalsIgnoreCase(item)) {
+ return true;
+ }
+ }
+ return false;
}
}
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/spring/policyrule/impl/EntityTrustMarkPolicyRuleParser.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/spring/policyrule/impl/EntityTrustMarkPolicyRuleParser.java
index 0891184..424ea9b 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/spring/policyrule/impl/EntityTrustMarkPolicyRuleParser.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/attribute/filter/spring/policyrule/impl/EntityTrustMarkPolicyRuleParser.java
@@ -17,9 +17,14 @@ package net.shibboleth.idp.plugin.oidc.op.oidfed.attribute.filter.spring.policyr
import javax.annotation.Nonnull;
import javax.xml.namespace.QName;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+
import net.shibboleth.idp.plugin.oidc.op.oidfed.attribute.filter.policyrule.impl.EntityTrustMarkPolicyRule;
import net.shibboleth.idp.plugin.oidc.op.oidfed.attribute.filter.spring.impl.AttributeFilterNamespaceHandler;
import net.shibboleth.idp.attribute.filter.spring.policyrule.impl.AbstractStringPolicyRuleParser;
+import net.shibboleth.shared.primitive.StringSupport;
/**
* Bean definition parser for {@link EntityTrustMarkPolicyRule}.
@@ -37,4 +42,15 @@ public class EntityTrustMarkPolicyRuleParser extends AbstractStringPolicyRulePar
return EntityTrustMarkPolicyRule.class;
}
+ /** {@inheritDoc} */
+ @Override
+ protected void doNativeParse(@Nonnull final Element element, @Nonnull final ParserContext parserContext,
+ @Nonnull final BeanDefinitionBuilder builder) {
+ super.doNativeParse(element, parserContext, builder);
+
+ if (element.hasAttributeNS(null, "clockSkew")) {
+ builder.addPropertyValue("clockSkew", StringSupport.trimOrNull(element.getAttributeNS(null, "clockSkew")));
+ }
+ }
+
}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
index adf351d..979ab13 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
@@ -14,6 +14,8 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl;
+import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -34,10 +36,14 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.oidfed.metadata.EntityStatement;
+import net.shibboleth.oidfed.metadata.TrustMark;
+import net.shibboleth.oidfed.metadata.util.EntityStatementHelper;
+import net.shibboleth.oidfed.profile.config.navigate.MaximumTrustMarkLifetimeLookupFunction;
import net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext;
import net.shibboleth.oidfed.profile.context.VerifiedTrustChain;
import net.shibboleth.oidfed.support.ClientInformationExtensionSupport;
import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -56,6 +62,9 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
/** Strategy used to lookup the trust chain context. */
@Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
+ /** Strategy used to lookup the maximum lifetime for trust marks. */
+ @Nonnull private Function<ProfileRequestContext, Duration> maximumTrustMarkLifetimeLookupStrategy;
+
/** Client information to operate on. */
@NonnullBeforeExec private OIDCClientInformation clientInformation;
@@ -65,6 +74,9 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
/** Selected trust chain to operate on. */
@NonnullBeforeExec private VerifiedTrustChain selectedTrustChain;
+ /** Maximum lifetime for trust marks. */
+ @NonnullBeforeExec private Duration maximumTrustMarkLifetime;
+
/** Constructor. */
public AddExtensionsToClientInformation() {
final Function<ProfileRequestContext,OIDCClientRegistrationResponseContext> orcls =
@@ -77,6 +89,7 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
new InboundMessageContextLookup());
assert tcls != null;
trustChainContextLookupStrategy = tcls;
+ maximumTrustMarkLifetimeLookupStrategy = new MaximumTrustMarkLifetimeLookupFunction();
}
/**
@@ -106,10 +119,21 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
}
+ /**
+ * Set the strategy to lookup the maximum lifetime for trust marks.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setMaximumTrustMarkLifetimeLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, Duration> strategy) {
+ checkSetterPreconditions();
+ maximumTrustMarkLifetimeLookupStrategy =
+ Constraint.isNotNull(strategy, "MaximumTrustMarkLifetimeLookupStrategy cannot be null");
+ }
+
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
if (!super.doPreExecute(profileRequestContext)) {
return false;
}
@@ -138,6 +162,13 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
return false;
}
+ maximumTrustMarkLifetime = maximumTrustMarkLifetimeLookupStrategy.apply(profileRequestContext);
+ if (maximumTrustMarkLifetime == null) {
+ log.error("{} Could not resolve maximum trust mark lifetime", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return false;
+ }
+
return true;
}
@@ -154,13 +185,21 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
clientInformation.getOIDCMetadata().setCustomField(
ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_CHAIN,
trustChain.stream().map(es -> es.getJwt().serialize()).toList());
- final Map<String,List<String>> verifiedTrustMarks = trustChainContext.getVerifiedTrustMarkIds();
- if (verifiedTrustMarks != null) {
- clientInformation.getOIDCMetadata().setCustomField(
- ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_MARK_IDS, verifiedTrustMarks);
+ final Map<String,List<TrustMark>> verifiedTrustMarks = trustChainContext.getVerifiedTrustMarks();
+ if (verifiedTrustMarks != null && !verifiedTrustMarks.isEmpty()) {
+ assert maximumTrustMarkLifetime != null;
+ final Map<String,List<Pair<String,Instant>>> result =
+ EntityStatementHelper.parseExpirableTrustMarkIds(verifiedTrustMarks, maximumTrustMarkLifetime);
+ if (result == null) {
+ log.warn("{} Could not parse expirable trust marks", getLogPrefix());
+ return;
+ }
+ log.debug("{} Set trust mark IDs extension to the client information: {}", getLogPrefix(), result);
+ assert clientInformation != null;
+ ClientInformationExtensionSupport.addValidatedTrustMarkIds(clientInformation, result);
+ } else {
+ log.trace("{} No trust marks resolved to be included in the client information", getLogPrefix());
}
-
-
}
}
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java
index 72307e3..8f53f8f 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java
@@ -14,43 +14,29 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl;
+import java.time.Duration;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.function.BiFunction;
import java.util.function.Function;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
import org.slf4j.Logger;
-import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.context.AutomaticRegistrationContext;
-import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
-import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
-import net.shibboleth.oidfed.metadata.EntityStatement;
-import net.shibboleth.oidfed.metadata.payload.claim.impl.MetadataImpl;
+import net.shibboleth.oidfed.metadata.TrustMark;
+import net.shibboleth.oidfed.metadata.util.EntityStatementHelper;
import net.shibboleth.oidfed.profile.config.navigate.ClaimsSetDecorationTypeLookupFunction;
-import net.shibboleth.oidfed.profile.config.navigate.LocalMetadataPolicyLookupFunction;
-import net.shibboleth.oidfed.profile.config.navigate.MandatoryTrustMarksLookupFunction;
+import net.shibboleth.oidfed.profile.config.navigate.MaximumTrustMarkLifetimeLookupFunction;
import net.shibboleth.oidfed.profile.config.navigate.ProvidedChainClaimsSetDecorationTypeLookupFunction;
-import net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext;
-import net.shibboleth.oidfed.profile.context.VerifiedTrustChain;
-import net.shibboleth.oidfed.profile.navigate.DefaultSelectedTrustChainMetadataLookupStrategy;
import net.shibboleth.oidfed.support.ClientInformationExtensionSupport;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
-import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -58,84 +44,45 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.action.ActionSupport;
/**
- * Resolves metadata policy-compliant trust chains from the configurable trust chain cache, metadata policy merging
- * strategy and enforcer. The data is populated to the {@link RelyingPartyTrustChainContext}.
+ * Extends {@link ValidateFederationRegistrationProfileConfiguration} by including the parsed trust mark IDs and their
+ * expiration instants into the client information object and calling the configured claims set decorator.
*
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_MSG_CTX}
* @event {@link ValidateAutomaticRegistrationProfileConfiguration#RESELECT_TRUST_CHAIN}
*/
-public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractProfileAction {
-
- /** ID of event returned if a flow wishes to indicate that another trust chain should be selected instead. */
- @Nonnull @NotEmpty public static final String RESELECT_TRUST_CHAIN = "ReselectTrustChain";
+public class ValidateAutomaticRegistrationProfileConfiguration
+ extends ValidateFederationRegistrationProfileConfiguration {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateAutomaticRegistrationProfileConfiguration.class);
- /** Strategy used to lookup the trust chain context. */
- @Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
-
/** Strategy used to create the automatic registration context. */
@Nonnull
private Function<ProfileRequestContext, AutomaticRegistrationContext> automaticRegistrationContextCreationStrategy;
- /** Strategy used to lookup the selected metadata. */
- @Nonnull private Function<ProfileRequestContext, OIDCClientMetadata> selectedMetadataLookupStrategy;
-
- /** Strategy used to lookup mandatory trust marks. */
- @Nonnull private Function<ProfileRequestContext, List<String>> mandatoryTrustMarksLookupStrategy;
-
- /** Strategy used to lookup local metadata policy to be merged to the client metadata. */
- @Nonnull private Function<ProfileRequestContext, Map<String, MetadataPolicy>> localMetadataPolicyLookupStrategy;
-
- /** Strategy used to merge local metadata policy into the client metadata. */
- @NonnullAfterInit private BiFunction<OIDCClientInformation,Map<String, MetadataPolicy>,OIDCClientInformation>
- localMetadataPolicyMergingStrategy;
-
/** Strategy used to lookup claims set decoration type. */
@Nonnull private Function<ProfileRequestContext, String> claimsSetDecorationTypeLookupStrategy;
/** Strategy used to lookup claims set decoration type for clients with request-provided trust chain. */
@Nonnull private Function<ProfileRequestContext, String> providedChainClaimsSetDecorationTypeLookupStrategy;
- /** Trust chain context to operate on. */
- @NonnullBeforeExec private RelyingPartyTrustChainContext trustChainContext;
-
- /** Selected trust chain to operate on. */
- @NonnullBeforeExec private VerifiedTrustChain selectedTrustChain;
+ /** Strategy used to lookup the maximum lifetime for trust marks. */
+ @Nonnull private Function<ProfileRequestContext, Duration> maximumTrustMarkLifetimeLookupStrategy;
/**
* Constructor.
*/
public ValidateAutomaticRegistrationProfileConfiguration() {
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
- new ChildContextLookup<>(RelyingPartyTrustChainContext.class).compose(
- new InboundMessageContextLookup());
- assert tcls != null;
- trustChainContextLookupStrategy = tcls;
+ super();
final Function<ProfileRequestContext, AutomaticRegistrationContext> arccs =
new ChildContextLookup<>(AutomaticRegistrationContext.class, true).compose(
new InboundMessageContextLookup());
assert arccs != null;
automaticRegistrationContextCreationStrategy = arccs;
- selectedMetadataLookupStrategy = new DefaultSelectedTrustChainMetadataLookupStrategy();
- mandatoryTrustMarksLookupStrategy = new MandatoryTrustMarksLookupFunction();
- localMetadataPolicyLookupStrategy = new LocalMetadataPolicyLookupFunction();
claimsSetDecorationTypeLookupStrategy = new ClaimsSetDecorationTypeLookupFunction();
providedChainClaimsSetDecorationTypeLookupStrategy = new ProvidedChainClaimsSetDecorationTypeLookupFunction();
- }
-
- /**
- * Set the strategy used to lookup the trust chain context.
- *
- * @param strategy lookup strategy
- */
- public void setTrustChainContextLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, RelyingPartyTrustChainContext> strategy) {
- checkSetterPreconditions();
- trustChainContextLookupStrategy =
- Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
+ maximumTrustMarkLifetimeLookupStrategy = new MaximumTrustMarkLifetimeLookupFunction();
}
/**
@@ -150,54 +97,6 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
Constraint.isNotNull(strategy, "AutomaticRegistrationContextCreationStrategy cannot be null");
}
- /**
- * Set the strategy used to lookup the selected metadata.
- *
- * @param strategy lookup strategy
- */
- public void setSelectedMetadataLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, OIDCClientMetadata> strategy) {
- checkSetterPreconditions();
- selectedMetadataLookupStrategy =
- Constraint.isNotNull(strategy, "SelectedMetadataLookupStrategy cannot be null");
- }
-
- /**
- * Set the strategy used to lookup mandatory trust marks.
- *
- * @param strategy lookup strategy
- */
- public void setMandatoryTrustMarksLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, List<String>> strategy) {
- checkSetterPreconditions();
- mandatoryTrustMarksLookupStrategy = Constraint.isNotNull(strategy,
- "Mandatory trust marks lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to lookup local metadata policy to be merged to the client metadata.
- *
- * @param strategy lookup strategy
- */
- public void setLocalMetadataPolicyLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, Map<String, MetadataPolicy>> strategy) {
- checkSetterPreconditions();
- localMetadataPolicyLookupStrategy = Constraint.isNotNull(strategy,
- "Local metadata policy lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to merge local metadata policy into the client metadata.
- *
- * @param strategy lookup strategy
- */
- public void setLocalMetadataPolicyMergingStrategy(@Nonnull
- final BiFunction<OIDCClientInformation,Map<String, MetadataPolicy>,OIDCClientInformation> strategy) {
- checkSetterPreconditions();
- localMetadataPolicyMergingStrategy =
- Constraint.isNotNull(strategy, "Local metadata policy merging strategy cannot be null");
- }
-
/**
* Set the strategy used to lookup claims set decoration type.
*
@@ -222,109 +121,51 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
Constraint.isNotNull(strategy, "Claims set decoration type lookup strategy cannot be null");
}
- /** {@inheritDoc} */
- @Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- if (!super.doPreExecute(profileRequestContext)) {
- return false;
- }
-
- trustChainContext = trustChainContextLookupStrategy.apply(profileRequestContext);
- if (trustChainContext == null || trustChainContext.getSelectedTrustChain() == null) {
- log.error("{} Unable to locate selected trust chain", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return false;
- }
+ /**
+ * Set the strategy to lookup the maximum lifetime for trust marks.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setMaximumTrustMarkLifetimeLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, Duration> strategy) {
+ checkSetterPreconditions();
+ maximumTrustMarkLifetimeLookupStrategy =
+ Constraint.isNotNull(strategy, "MaximumTrustMarkLifetimeLookupStrategy cannot be null");
+ }
- selectedTrustChain = trustChainContext.getSelectedTrustChain();
- if (selectedTrustChain == null) {
- log.error("{} Selected trust chain contents is not populated", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ protected boolean extendedExecution(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final OIDCClientInformation clientInformation) {
+
+ final Duration maximumTrustMarkLifetime = maximumTrustMarkLifetimeLookupStrategy.apply(profileRequestContext);
+ if (maximumTrustMarkLifetime == null) {
+ log.error("{} Could not resolve maximum trust mark lifetime", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
return false;
}
- return true;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- final OIDCClientMetadata metadata = selectedMetadataLookupStrategy.apply(profileRequestContext);
- if (metadata == null) {
- log.error("{} Unable to parse the RP metadata for storing", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return;
- }
- final OIDCClientInformation clientInformation;
- final Map<String, MetadataPolicy> localMetadataPolicy =
- localMetadataPolicyLookupStrategy.apply(profileRequestContext);
- if (localMetadataPolicy != null && !localMetadataPolicy.isEmpty()) {
- log.debug("{} Applying local metadata policy into the client metadata", getLogPrefix());
- clientInformation = localMetadataPolicyMergingStrategy.apply(
- new OIDCClientInformation(
- new ClientID(selectedTrustChain.getTrustChain().get(0).getSubject()),
- metadata), localMetadataPolicy);
- if (clientInformation == null) {
- log.error("{} Could not apply the local metadata policy into the client metadata", getLogPrefix());
+ final Map<String,List<TrustMark>> verifiedTrustMarks = trustChainContext.getVerifiedTrustMarks();
+ if (verifiedTrustMarks != null && !verifiedTrustMarks.isEmpty()) {
+ assert maximumTrustMarkLifetime != null;
+ final Map<String,List<Pair<String,Instant>>> result =
+ EntityStatementHelper.parseExpirableTrustMarkIds(verifiedTrustMarks, maximumTrustMarkLifetime);
+ if (result == null) {
+ log.error("{} Could not parse expirable trust marks", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return;
+ return false;
}
- final MetadataImpl selectedMetadata = new MetadataImpl();
- selectedMetadata.setOpenidRelyingPartyMetadata(clientInformation.toJSONObject());
- selectedTrustChain.setMetadata(selectedMetadata);
+ log.debug("{} Set trust mark IDs extension to the client information: {}", getLogPrefix(), result);
+ ClientInformationExtensionSupport.addValidatedTrustMarkIds(clientInformation, result);
} else {
- clientInformation = new OIDCClientInformation(
- new ClientID(selectedTrustChain.getTrustChain().get(0).getSubject()), metadata);
-
- }
- final String clientId = clientInformation.getID().getValue();
- final Map<String,List<String>> verifiedTrustMarks = trustChainContext.getVerifiedTrustMarkIds();
- final List<String> mandatoryTrustMarks = mandatoryTrustMarksLookupStrategy.apply(profileRequestContext);
- if (mandatoryTrustMarks != null && !mandatoryTrustMarks.isEmpty()) {
- log.debug("{} Verifying the mandatory trust marks {}", getLogPrefix(), mandatoryTrustMarks);
- if (verifiedTrustMarks == null || verifiedTrustMarks.get(clientId) == null
- || !verifiedTrustMarks.get(clientId).containsAll(mandatoryTrustMarks)) {
- log.info("{} Rejecting registration as some of the following mandatory trust marks are missing: {}",
- getLogPrefix(), mandatoryTrustMarks);
- final List<List<EntityStatement<?>>> rejectedTrustChains = trustChainContext.getRejectedTrustChains();
- if (rejectedTrustChains == null) {
- trustChainContext.setRejectedTrustChains(List.of(selectedTrustChain.getTrustChain()));
- } else {
- final List<List<EntityStatement<?>>> rejectedChains = new ArrayList<>(rejectedTrustChains);
- rejectedChains.add(selectedTrustChain.getTrustChain());
- trustChainContext.setRejectedTrustChains(CollectionSupport.copyToList(rejectedChains));
- }
- ActionSupport.buildEvent(profileRequestContext, RESELECT_TRUST_CHAIN);
- return;
- }
- }
-
- final List<EntityStatement<?>> trustChain = selectedTrustChain.getTrustChain();
- assert trustChain != null;
- trustChainContext.setSelectedMetadataExpiration(resolveTrustChainExpiration(trustChain));
-
- final OIDCMetadataContext oidcCtx = new OIDCMetadataContext();
- clientInformation.getOIDCMetadata().setCustomField(
- ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_ANCHOR,
- trustChain.get(trustChain.size() - 1).getSubject());
- clientInformation.getOIDCMetadata().setCustomField(
- ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_CHAIN,
- trustChain.stream().map(es -> es.getJwt().serialize()).toList());
- if (verifiedTrustMarks != null) {
- clientInformation.getOIDCMetadata().setCustomField(
- ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_MARK_IDS, verifiedTrustMarks);
+ log.trace("{} No trust marks resolved to be included in the client information", getLogPrefix());
}
log.debug("{} Client information after adding custom extension {}", getLogPrefix(),
clientInformation.toJSONObject().toJSONString());
- oidcCtx.setClientInformation(clientInformation);
- profileRequestContext.ensureInboundMessageContext().addSubcontext(oidcCtx);
- log.debug("{} Client information attached to the OIDCMetadataContext", getLogPrefix());
final AutomaticRegistrationContext automaticRegistrationContext =
automaticRegistrationContextCreationStrategy.apply(profileRequestContext);
if (automaticRegistrationContext == null) {
log.error("{} Could not create automatic registration context", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return;
+ return false;
}
final String decorationType;
if (trustChainContext.getProvidedTrustChain() != null) {
@@ -335,21 +176,6 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
log.debug("{} Resolved default claims set decoration type {}", getLogPrefix(), decorationType);
}
automaticRegistrationContext.setClaimsSetDecorationType(decorationType);
- }
-
- /**
- * Resolve expiration time for the given trust chain.
- *
- * @param trustChain trust chain
- * @return expiration time
- */
- @Nullable private Instant resolveTrustChainExpiration(@Nonnull final List<EntityStatement<?>> trustChain) {
- Instant metadataExpiration = null;
- for (final EntityStatement<?> statement : trustChain) {
- final Instant statementExpiration = statement.getParsedPayload().getExpiration();
- metadataExpiration = metadataExpiration == null ? statementExpiration :
- statementExpiration.isBefore(metadataExpiration) ? statementExpiration : metadataExpiration;
- }
- return metadataExpiration;
+ return true;
}
}
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateFederationRegistrationProfileConfiguration.java
similarity index 73%
copy from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java
copy to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateFederationRegistrationProfileConfiguration.java
index 72307e3..27dc0bd 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateAutomaticRegistrationProfileConfiguration.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateFederationRegistrationProfileConfiguration.java
@@ -33,16 +33,13 @@ import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.context.AutomaticRegistrationContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
import net.shibboleth.oidfed.metadata.EntityStatement;
import net.shibboleth.oidfed.metadata.payload.claim.impl.MetadataImpl;
-import net.shibboleth.oidfed.profile.config.navigate.ClaimsSetDecorationTypeLookupFunction;
import net.shibboleth.oidfed.profile.config.navigate.LocalMetadataPolicyLookupFunction;
import net.shibboleth.oidfed.profile.config.navigate.MandatoryTrustMarksLookupFunction;
-import net.shibboleth.oidfed.profile.config.navigate.ProvidedChainClaimsSetDecorationTypeLookupFunction;
import net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext;
import net.shibboleth.oidfed.profile.context.VerifiedTrustChain;
import net.shibboleth.oidfed.profile.navigate.DefaultSelectedTrustChainMetadataLookupStrategy;
@@ -63,23 +60,19 @@ import org.opensaml.profile.action.ActionSupport;
*
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_MSG_CTX}
- * @event {@link ValidateAutomaticRegistrationProfileConfiguration#RESELECT_TRUST_CHAIN}
+ * @event {@link ValidateFederationRegistrationProfileConfiguration#RESELECT_TRUST_CHAIN}
*/
-public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractProfileAction {
+public class ValidateFederationRegistrationProfileConfiguration extends AbstractProfileAction {
/** ID of event returned if a flow wishes to indicate that another trust chain should be selected instead. */
@Nonnull @NotEmpty public static final String RESELECT_TRUST_CHAIN = "ReselectTrustChain";
/** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(ValidateAutomaticRegistrationProfileConfiguration.class);
+ @Nonnull private Logger log = LoggerFactory.getLogger(ValidateFederationRegistrationProfileConfiguration.class);
/** Strategy used to lookup the trust chain context. */
@Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
- /** Strategy used to create the automatic registration context. */
- @Nonnull
- private Function<ProfileRequestContext, AutomaticRegistrationContext> automaticRegistrationContextCreationStrategy;
-
/** Strategy used to lookup the selected metadata. */
@Nonnull private Function<ProfileRequestContext, OIDCClientMetadata> selectedMetadataLookupStrategy;
@@ -93,37 +86,24 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
@NonnullAfterInit private BiFunction<OIDCClientInformation,Map<String, MetadataPolicy>,OIDCClientInformation>
localMetadataPolicyMergingStrategy;
- /** Strategy used to lookup claims set decoration type. */
- @Nonnull private Function<ProfileRequestContext, String> claimsSetDecorationTypeLookupStrategy;
-
- /** Strategy used to lookup claims set decoration type for clients with request-provided trust chain. */
- @Nonnull private Function<ProfileRequestContext, String> providedChainClaimsSetDecorationTypeLookupStrategy;
-
/** Trust chain context to operate on. */
- @NonnullBeforeExec private RelyingPartyTrustChainContext trustChainContext;
+ @NonnullBeforeExec protected RelyingPartyTrustChainContext trustChainContext;
/** Selected trust chain to operate on. */
- @NonnullBeforeExec private VerifiedTrustChain selectedTrustChain;
+ @NonnullBeforeExec protected VerifiedTrustChain selectedTrustChain;
/**
* Constructor.
*/
- public ValidateAutomaticRegistrationProfileConfiguration() {
+ public ValidateFederationRegistrationProfileConfiguration() {
final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
new ChildContextLookup<>(RelyingPartyTrustChainContext.class).compose(
new InboundMessageContextLookup());
assert tcls != null;
trustChainContextLookupStrategy = tcls;
- final Function<ProfileRequestContext, AutomaticRegistrationContext> arccs =
- new ChildContextLookup<>(AutomaticRegistrationContext.class, true).compose(
- new InboundMessageContextLookup());
- assert arccs != null;
- automaticRegistrationContextCreationStrategy = arccs;
selectedMetadataLookupStrategy = new DefaultSelectedTrustChainMetadataLookupStrategy();
mandatoryTrustMarksLookupStrategy = new MandatoryTrustMarksLookupFunction();
localMetadataPolicyLookupStrategy = new LocalMetadataPolicyLookupFunction();
- claimsSetDecorationTypeLookupStrategy = new ClaimsSetDecorationTypeLookupFunction();
- providedChainClaimsSetDecorationTypeLookupStrategy = new ProvidedChainClaimsSetDecorationTypeLookupFunction();
}
/**
@@ -138,18 +118,6 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
}
- /**
- * Set the strategy used to create automatic registration context.
- *
- * @param strategy creation strategy
- */
- public void setAutomaticRegistrationContextCreationStrategy(
- @Nonnull final Function<ProfileRequestContext, AutomaticRegistrationContext> strategy) {
- checkSetterPreconditions();
- automaticRegistrationContextCreationStrategy =
- Constraint.isNotNull(strategy, "AutomaticRegistrationContextCreationStrategy cannot be null");
- }
-
/**
* Set the strategy used to lookup the selected metadata.
*
@@ -198,30 +166,6 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
Constraint.isNotNull(strategy, "Local metadata policy merging strategy cannot be null");
}
- /**
- * Set the strategy used to lookup claims set decoration type.
- *
- * @param strategy lookup strategy
- */
- public void setClaimsSetDecorationTypeLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, String> strategy) {
- checkSetterPreconditions();
- claimsSetDecorationTypeLookupStrategy =
- Constraint.isNotNull(strategy, "Claims set decoration type lookup strategy cannot be null");
- }
-
- /**
- * Set the strategy used to lookup claims set decoration type for clients with request-provided trust chain.
- *
- * @param strategy lookup strategy
- */
- public void setProvidedChainClaimsSetDecorationTypeLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, String> strategy) {
- checkSetterPreconditions();
- providedChainClaimsSetDecorationTypeLookupStrategy =
- Constraint.isNotNull(strategy, "Claims set decoration type lookup strategy cannot be null");
- }
-
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
@@ -310,31 +254,28 @@ public class ValidateAutomaticRegistrationProfileConfiguration extends AbstractP
clientInformation.getOIDCMetadata().setCustomField(
ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_CHAIN,
trustChain.stream().map(es -> es.getJwt().serialize()).toList());
- if (verifiedTrustMarks != null) {
- clientInformation.getOIDCMetadata().setCustomField(
- ClientInformationExtensionSupport.KEY_VALIDATED_TRUST_MARK_IDS, verifiedTrustMarks);
+
+ if (!extendedExecution(profileRequestContext, clientInformation)) {
+ log.debug("{} Extended execution returned false", getLogPrefix());
+ return;
}
- log.debug("{} Client information after adding custom extension {}", getLogPrefix(),
- clientInformation.toJSONObject().toJSONString());
+
oidcCtx.setClientInformation(clientInformation);
profileRequestContext.ensureInboundMessageContext().addSubcontext(oidcCtx);
log.debug("{} Client information attached to the OIDCMetadataContext", getLogPrefix());
- final AutomaticRegistrationContext automaticRegistrationContext =
- automaticRegistrationContextCreationStrategy.apply(profileRequestContext);
- if (automaticRegistrationContext == null) {
- log.error("{} Could not create automatic registration context", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
- return;
- }
- final String decorationType;
- if (trustChainContext.getProvidedTrustChain() != null) {
- decorationType = providedChainClaimsSetDecorationTypeLookupStrategy.apply(profileRequestContext);
- log.debug("{} Resolved provided chain claims set decoration type {}", getLogPrefix(), decorationType);
- } else {
- decorationType = claimsSetDecorationTypeLookupStrategy.apply(profileRequestContext);
- log.debug("{} Resolved default claims set decoration type {}", getLogPrefix(), decorationType);
- }
- automaticRegistrationContext.setClaimsSetDecorationType(decorationType);
+ }
+
+ /**
+ * The extension hooks for the classes extending this action. If the extension run is not successful, in addition
+ * to returning false the extension is expected to build appropriate event regarding the error.
+ *
+ * @param profileRequestContext profile request context
+ * @param clientInformation client information that will be added to {@link OIDCMetadataContext}
+ * @return true if execution was successful, false otherwise
+ */
+ protected boolean extendedExecution(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final OIDCClientInformation clientInformation) {
+ return true;
}
/**
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 c465923..d71596b 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
@@ -282,6 +282,10 @@
<bean class="net.shibboleth.oidfed.profile.config.navigate.ProvidedChainClaimsSetDecorationTypeLookupFunction"
p:relyingPartyContextLookupStrategy-ref="AutomaticRegistrationRelyingPartyCreationStrategy"/>
</property>
+ <property name="maximumTrustMarkLifetimeLookupStrategy">
+ <bean class="net.shibboleth.oidfed.profile.config.navigate.MaximumTrustMarkLifetimeLookupFunction"
+ p:relyingPartyContextLookupStrategy-ref="AutomaticRegistrationRelyingPartyCreationStrategy"/>
+ </property>
</bean>
</beans>
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 d4390e0..8b9eec8 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
@@ -397,7 +397,7 @@
p:metadataPolicyValidationStrategy="#{getObject('shibboleth.oidc.dynreg.MetadataPolicyValidator') ?: getObject('shibboleth.oidc.dynreg.DefaultMetadataPolicyValidator')}" />
<bean id="ValidateExplicitRegistrationProfileConfiguration"
- class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.ValidateAutomaticRegistrationProfileConfiguration"
+ class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.ValidateFederationRegistrationProfileConfiguration"
scope="prototype">
<property name="localMetadataPolicyMergingStrategy">
<bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultLocalMetadataPolicyMergingStrategy"
diff --git a/idp-oidfed-op-impl/src/main/resources/schema/shibboleth-afp-oidfed.xsd b/idp-oidfed-op-impl/src/main/resources/schema/shibboleth-afp-oidfed.xsd
index 5f57c35..b1971a3 100644
--- a/idp-oidfed-op-impl/src/main/resources/schema/shibboleth-afp-oidfed.xsd
+++ b/idp-oidfed-op-impl/src/main/resources/schema/shibboleth-afp-oidfed.xsd
@@ -17,8 +17,14 @@
</documentation>
</annotation>
<complexContent>
- <extension base="afp:StringMatchType" />
+ <extension base="afp:StringMatchType">
+ <attribute name="clockSkew" type="afp:string">
+ <annotation>
+ <documentation>The clock skew value to use for calculating expiration time for trust marks. Time is expressed in ISO8601 duration format.</documentation>
+ </annotation>
+ </attribute>
+ </extension>
</complexContent>
</complexType>
-</schema>
\ No newline at end of file
+</schema>
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
index d29b5e8..07d6373 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
@@ -14,11 +14,17 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow.oidfed;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
+import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -32,6 +38,7 @@ import org.testng.annotations.Test;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.oauth2.sdk.OAuth2Error;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.id.ClientID;
@@ -122,6 +129,64 @@ public class UserInfoFlowAutomaticRegistrationTest extends AbstractFederationFlo
Assert.assertNull(response.getUserInfoJWT());
}
+ @Test
+ public void testSuccess_explicit_extraClaimViaTrustMark() throws URISyntaxException, NoSuchAlgorithmException,
+ DataSealerException, ComponentInitializationException, IOException {
+ final String clientId = uniqueClientId();
+
+ final OIDCClientMetadata metadata = new OIDCClientMetadata();
+ metadata.setRedirectionURI(new URI(redirectUri));
+ metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+ final String trustMark = FederationJwtSupport.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey,
+ trustMarkIssuerId, clientId, "https://example.org/email-allowing-trust-mark",
+ Instant.now().plusSeconds(300)).serialize();
+
+ final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().issuer(clientId).subject(clientId)
+ .issueTime(Date.from(Instant.now()))
+ .expirationTime(Date.from(Instant.now().plusSeconds(300)))
+ .audience(issuer)
+ .claim("jwks", new JWKSet(leafKey).toJSONObject(true))
+ .claim("metadata", Map.of("openid_relying_party", metadata.toJSONObject()))
+ .claim("authority_hints", new String[] { anchorId })
+ .claim("trust_marks", List.of(Map.of(
+ "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+ "trust_mark", trustMark)));
+ final String explicitRegistrationRequest =
+ FederationJwtSupport.entityStatement(JWSAlgorithm.RS256, leafKey, builder.build()).serialize();
+
+ rpConfigureMockHttpClient(clientId);
+ try {
+ mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+ mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+ mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+ mockResponse(subordinateStatement(trustMarkIssuerId,
+ Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+ mapResponse(trustMarkStatusEndpoint, mockResponse(200, "application/trust-mark-status-response+jwt",
+ trustMarkStatusResponse(trustMarkIssuerId, trustMark, "active", trustMarkIssuerKey)));
+ } catch (UnsupportedOperationException | IOException e) {
+ Assert.fail("Could not initialize mock HTTP client", e);
+ }
+ setRequest("POST", explicitRegistrationRequest, "application/entity-statement+jwt");
+ flowExecutor.launchExecution(RegistrationFlowTest.FLOW_ID, null, externalContext);
+ verify(federationHttpClient, times(0)).executeOpen(any(),
+ argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
+
+ initializeMocks();
+ initializeThreadLocals();
+ request.setMethod("GET");
+
+ final BearerAccessToken token = buildToken(clientId, List.of(clientId, anchorId));
+ request.addHeader("Authorization", token.toAuthorizationHeader());
+ final FlowExecutionResult result = flowExecutor.launchExecution(UserInfoTest.FLOW_ID, null, externalContext);
+ final UserInfoSuccessResponse response = parseSuccessResponse(result, UserInfoSuccessResponse.class);
+ Assert.assertEquals(response.getUserInfo().getSubject().getValue(), subject);
+ final UserInfo userInfo = response.getUserInfo();
+ Assert.assertNotNull(userInfo);
+ Assert.assertEquals(userInfo.getEmailAddress(), "jdoe at example.org");
+ Assert.assertNull(userInfo.getNickname());
+ Assert.assertNull(response.getUserInfoJWT());
+ }
+
@Test
public void testSuccess_resolveApi() throws Exception {
final String clientId = uniqueClientId();
diff --git a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/attribute-filter.xml b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/attribute-filter.xml
index 606841a..b2a1981 100644
--- a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/attribute-filter.xml
+++ b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/attribute-filter.xml
@@ -132,7 +132,7 @@
</AttributeFilterPolicy>
<AttributeFilterPolicy id="OIDFED_EMAIL">
- <PolicyRequirementRule xsi:type="oidfed:OIDFEDEntityTrustMark" value="https://example.org/email-allowing-trust-mark" />
+ <PolicyRequirementRule xsi:type="oidfed:OIDFEDEntityTrustMark" value="https://example.org/email-allowing-trust-mark" clockSkew="PT30S"/>
<AttributeRule attributeID="mail">
<PermitValueRule xsi:type="ANY" />
</AttributeRule>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list