[java-idp-oidc] branch dev/JOIDC-222 updated: JOIDC-222 - Support for OpenID Federation
Henri Mikkonen
henri.mikkonen at iki.fi
Thu Mar 20 07:05:06 UTC 2025
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch dev/JOIDC-222
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=d6e5a65b7a2811b05ff10965d52b0b130a702f3e
The following commit(s) were added to refs/heads/dev/JOIDC-222 by this push:
new d6e5a65b JOIDC-222 - Support for OpenID Federation
d6e5a65b is described below
commit d6e5a65b7a2811b05ff10965d52b0b130a702f3e
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Mar 20 09:04:52 2025 +0200
JOIDC-222 - Support for OpenID Federation
https://shibboleth.atlassian.net/browse/JOIDC-222
- Refactor lookup functions dealing with RelyingPartyTrustChainContext
- Add 'trust_anchor' and 'authority_hints' claims to the explicit registration response
---
.../impl/BuildExplicitRegistrationResponse.java | 57 ++++++++++++++++++++--
...> AbstractTrustChainContextLookupFunction.java} | 57 ++++++++++++----------
...DefaultSelectedTrustChainIDsLookupStrategy.java | 47 ++++--------------
...dTrustChainImmediateSuperiorLookupStrategy.java | 42 ++++++++++++++++
...ltSelectedTrustChainMetadataLookupStrategy.java | 41 ++--------------
...electedTrustChainTrustAnchorLookupStrategy.java | 41 ++++++++++++++++
.../DefaultTrustChainSelectionStrategy.java | 42 ++--------------
.../profile/flow/oidfed/RegistrationFlowTest.java | 15 ++++--
8 files changed, 196 insertions(+), 146 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
index 368ea369..77742f8a 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
@@ -16,6 +16,7 @@ package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl;
import java.time.Instant;
import java.util.Date;
+import java.util.List;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -33,11 +34,14 @@ import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultSelectedTrustChainImmediateSuperiorLookupStrategy;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultSelectedTrustChainTrustAnchorLookupStrategy;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.ExplicitClientRegistrationRequestJWKSetLookupFunction;
import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
/**
* An action that uses the information from {@link OIDCClientRegistrationResponseContext} attached to the message
@@ -59,6 +63,12 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
/** Strategy used to lookup the trust chain context. */
@Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
+ /** Strategy used to lookup the trust anchor. */
+ @Nonnull private Function<ProfileRequestContext, String> trustAnchorLookupStrategy;
+
+ /** Strategy used to lookup the immediate superior used for the authority_hints claim. */
+ @Nonnull private Function<ProfileRequestContext, String> immediateSuperiorLookupStrategy;
+
/** The {@link OIDCClientRegistrationResponseContext} to operate on. */
@NonnullBeforeExec private OIDCClientRegistrationResponseContext oidcResponseContext;
@@ -78,6 +88,8 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
new InboundMessageContextLookup());
assert tcls != null;
trustChainContextLookupStrategy = tcls;
+ trustAnchorLookupStrategy = new DefaultSelectedTrustChainTrustAnchorLookupStrategy();
+ immediateSuperiorLookupStrategy = new DefaultSelectedTrustChainImmediateSuperiorLookupStrategy();
}
/**
@@ -115,6 +127,27 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
}
+ /**
+ * Set the strategy used to lookup the trust anchor.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setTrustAnchorLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ checkSetterPreconditions();
+ trustAnchorLookupStrategy = Constraint.isNotNull(strategy, "TrustAnchorLookupStrategy cannot be null");
+ }
+
+ /**
+ * Set the strategy used to lookup the immediate superior used for the authority_hints claim.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setImmediateSuperiorLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ checkSetterPreconditions();
+ immediateSuperiorLookupStrategy =
+ Constraint.isNotNull(strategy, "ImmediateSuperiorLookupStrategy cannot be null");
+ }
+
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
@@ -131,8 +164,8 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
}
trustChainContext = trustChainContextLookupStrategy.apply(profileRequestContext);
- if (trustChainContext == null || trustChainContext.getPolicyCompliantTrustChains() == null) {
- log.error("{} Unable to locate policy-compliant trust chains", getLogPrefix());
+ if (trustChainContext == null) {
+ log.error("{} Unable to locate trust chain context", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
return false;
}
@@ -152,6 +185,7 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
}
builder.claim("metadata",
CollectionSupport.singletonMap("openid_relying_party", clientInformation.toJSONObject()));
+
final JWKSet jwkSet = jwkSetLookupStrategy.apply(profileRequestContext);
if (jwkSet == null) {
log.error("{} Coud not resolve JWK set to be included in the response statement", getLogPrefix());
@@ -159,6 +193,7 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
return false;
}
builder.claim("jwks", jwkSet.toJSONObject(true));
+
final Instant expirationTime = trustChainContext.getSelectedMetadataExpiration();
if (expirationTime == null) {
log.error("{} Coud not resolve expiration time from the selected trust chain context", getLogPrefix());
@@ -166,7 +201,23 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
return false;
}
builder.expirationTime(Date.from(expirationTime));
+
+ final String trustAnchor = trustAnchorLookupStrategy.apply(profileRequestContext);
+ if (StringSupport.trimOrNull(trustAnchor) == null) {
+ log.error("{} Unable to locate trust anchor from the context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+ builder.claim("trust_anchor", trustAnchor);
+
+ final String superior = immediateSuperiorLookupStrategy.apply(profileRequestContext);
+ if (StringSupport.trimOrNull(superior) == null) {
+ log.error("{} Unable to locate immediate superior from the context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+ builder.claim("authority_hints", List.of(superior));
+
return true;
}
-
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/AbstractTrustChainContextLookupFunction.java
similarity index 51%
copy from idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java
copy to idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/AbstractTrustChainContextLookupFunction.java
index 6780b041..1c6bcb6a 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/AbstractTrustChainContextLookupFunction.java
@@ -14,7 +14,6 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate;
-import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -23,19 +22,21 @@ import javax.annotation.Nullable;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+import org.slf4j.Logger;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
-import net.shibboleth.shared.annotation.ParameterName;
import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Default strategy for looking up the metadata the selected trust chain. The selected trust chain is fetched via
- * {@link RelyingPartyTrustChainContext#getSelectedTrustChain()}.
+ * An abstract function for lookup functions dealing with {@link RelyingPartyTrustChainContext}.
+ *
+ * @param <T> The return type of the lookup function
*/
-public class DefaultSelectedTrustChainMetadataLookupStrategy
- implements Function<ProfileRequestContext,OIDCClientMetadata> {
+public abstract class AbstractTrustChainContextLookupFunction<T> implements Function<ProfileRequestContext, T> {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(AbstractTrustChainContextLookupFunction.class);
/** Strategy used to locate the trust chain context. */
@Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
@@ -43,34 +44,40 @@ public class DefaultSelectedTrustChainMetadataLookupStrategy
/**
* Constructor.
*/
- public DefaultSelectedTrustChainMetadataLookupStrategy() {
+ public AbstractTrustChainContextLookupFunction() {
final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
- new ChildContextLookup<>(RelyingPartyTrustChainContext.class, true).compose(
+ new ChildContextLookup<>(RelyingPartyTrustChainContext.class).compose(
new InboundMessageContextLookup());
assert tcls != null;
trustChainContextLookupStrategy = tcls;
}
/**
- * Constructor.
- *
- * @param trustChainContextStrategy strategy used to locate the trust chain context
- * @param trustChainIDsStrategy strategy used to get entity IDs from a trust chain
+ * Set the strategy used to locate the trust chain context.
+ *
+ * @param strategy lookup strategy
*/
- public DefaultSelectedTrustChainMetadataLookupStrategy(
- @Nonnull @ParameterName(name = "trustChainContextLookupStrategy")
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextStrategy) {
+ public void setTrustChainContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, RelyingPartyTrustChainContext> strategy) {
trustChainContextLookupStrategy =
- Constraint.isNotNull(trustChainContextStrategy, "TrustChainContextLookupStrategy cannot be null");
+ Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
}
/** {@inheritDoc} */
- @Override @Nullable
- public OIDCClientMetadata apply(@Nullable final ProfileRequestContext input) {
- return Optional.ofNullable(trustChainContextLookupStrategy.apply(input))
- .map(trustChainContext -> trustChainContext.getSelectedTrustChain())
- .map(pair -> pair.getSecond())
- .map(clientInfo -> clientInfo.getOIDCMetadata())
- .orElse(null);
+ @Override @Nullable public T apply(@Nullable final ProfileRequestContext input) {
+ final RelyingPartyTrustChainContext trustChainContext = trustChainContextLookupStrategy.apply(input);
+ if (trustChainContext == null) {
+ log.error("Could not resolve trust chain context");
+ return null;
+ }
+ return doApply(trustChainContext);
}
+
+ /**
+ * Perform the lookup operation on the {@link RelyingPartyTrustChainContext}.
+ *
+ * @param trustChainContext the context, guaranteed to be non-null
+ * @return result
+ */
+ @Nullable protected abstract T doApply(@Nonnull final RelyingPartyTrustChainContext trustChainContext);
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainIDsLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainIDsLookupStrategy.java
index 75b87dd8..8344b48c 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainIDsLookupStrategy.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainIDsLookupStrategy.java
@@ -21,29 +21,16 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-import org.slf4j.Logger;
-
import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
-import net.shibboleth.shared.annotation.ParameterName;
import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
/**
* Default strategy for looking up the entity IDs of the selected trust chain. The selected trust chain is fetched via
* {@link RelyingPartyTrustChainContext#getSelectedTrustChain()}.
*/
-public class DefaultSelectedTrustChainIDsLookupStrategy implements Function<ProfileRequestContext,List<String>> {
-
- /** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(DefaultSelectedTrustChainIDsLookupStrategy.class);
-
- /** Strategy used to locate the trust chain context. */
- @Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
+public class DefaultSelectedTrustChainIDsLookupStrategy extends AbstractTrustChainContextLookupFunction<List<String>> {
/** Strategy used to get entity IDs from a trust chain. */
@Nonnull private Function<List<EntityStatement>, List<String>> trustChainIDsLookupStrategy;
@@ -52,39 +39,23 @@ public class DefaultSelectedTrustChainIDsLookupStrategy implements Function<Prof
* Constructor.
*/
public DefaultSelectedTrustChainIDsLookupStrategy() {
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
- new ChildContextLookup<>(RelyingPartyTrustChainContext.class, true).compose(
- new InboundMessageContextLookup());
- assert tcls != null;
- trustChainContextLookupStrategy = tcls;
+ super();
trustChainIDsLookupStrategy = new DefaultTrustChainIDsLookupStrategy();
}
/**
- * Constructor.
- *
- * @param trustChainContextStrategy strategy used to locate the trust chain context
- * @param trustChainIDsStrategy strategy used to get entity IDs from a trust chain
+ * Set the strategy used to get entity IDs from a trust chain.
+ *
+ * @param strategy lookup strategy
*/
- public DefaultSelectedTrustChainIDsLookupStrategy(
- @Nonnull @ParameterName(name = "trustChainContextLookupStrategy")
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextStrategy,
- @Nonnull @ParameterName(name = "trustChainIDsLookupStrategy")
- final Function<List<EntityStatement>, List<String>> trustChainIDsStrategy) {
- trustChainContextLookupStrategy =
- Constraint.isNotNull(trustChainContextStrategy, "TrustChainContextLookupStrategy cannot be null");
- trustChainIDsLookupStrategy =
- Constraint.isNotNull(trustChainIDsStrategy, "TrustChainIDsLookupStrategy cannot be null");
+ public void setTrustChainIDsLookupStrategy(
+ @Nonnull final Function<List<EntityStatement>, List<String>> strategy) {
+ trustChainIDsLookupStrategy = Constraint.isNotNull(strategy, "TrustChainIDsLookupStrategy cannot be null");
}
/** {@inheritDoc} */
@Override @Nullable
- public List<String> apply(@Nullable final ProfileRequestContext input) {
- final RelyingPartyTrustChainContext trustChainContext = trustChainContextLookupStrategy.apply(input);
- if (trustChainContext == null || trustChainContext.getSelectedTrustChain() == null) {
- log.debug("No selected trust chain located");
- return null;
- }
+ public List<String> doApply(@Nonnull final RelyingPartyTrustChainContext trustChainContext) {
return Optional.ofNullable(trustChainContext.getSelectedTrustChain())
.map(pair -> pair.getFirst())
.map(chain -> trustChainIDsLookupStrategy.apply(chain))
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainImmediateSuperiorLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainImmediateSuperiorLookupStrategy.java
new file mode 100644
index 00000000..f03a2a7d
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainImmediateSuperiorLookupStrategy.java
@@ -0,0 +1,42 @@
+/*
+ * 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.navigate;
+
+import java.util.Optional;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
+
+/**
+ * Default strategy for looking up the entity ID of the immediate superior in the selected trust chain. The selected
+ * trust chain is fetched via {@link RelyingPartyTrustChainContext#getSelectedTrustChain()}.
+ */
+public class DefaultSelectedTrustChainImmediateSuperiorLookupStrategy
+ extends AbstractTrustChainContextLookupFunction<String> {
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ public String doApply(@Nonnull final RelyingPartyTrustChainContext trustChainContext) {
+ return Optional.ofNullable(trustChainContext.getSelectedTrustChain())
+ .map(pair -> pair.getFirst())
+ .filter(list -> list.size() >= 3)
+ .map(list -> list.get(1))
+ .map(entityStatement -> entityStatement.getClaimsSet().getIssuer())
+ .map(issuer -> issuer.getValue())
+ .orElse(null);
+ }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java
index 6780b041..205c2c6c 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainMetadataLookupStrategy.java
@@ -15,60 +15,25 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate;
import java.util.Optional;
-import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
-import net.shibboleth.shared.annotation.ParameterName;
-import net.shibboleth.shared.logic.Constraint;
/**
* Default strategy for looking up the metadata the selected trust chain. The selected trust chain is fetched via
* {@link RelyingPartyTrustChainContext#getSelectedTrustChain()}.
*/
public class DefaultSelectedTrustChainMetadataLookupStrategy
- implements Function<ProfileRequestContext,OIDCClientMetadata> {
-
- /** Strategy used to locate the trust chain context. */
- @Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
-
- /**
- * Constructor.
- */
- public DefaultSelectedTrustChainMetadataLookupStrategy() {
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
- new ChildContextLookup<>(RelyingPartyTrustChainContext.class, true).compose(
- new InboundMessageContextLookup());
- assert tcls != null;
- trustChainContextLookupStrategy = tcls;
- }
-
- /**
- * Constructor.
- *
- * @param trustChainContextStrategy strategy used to locate the trust chain context
- * @param trustChainIDsStrategy strategy used to get entity IDs from a trust chain
- */
- public DefaultSelectedTrustChainMetadataLookupStrategy(
- @Nonnull @ParameterName(name = "trustChainContextLookupStrategy")
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextStrategy) {
- trustChainContextLookupStrategy =
- Constraint.isNotNull(trustChainContextStrategy, "TrustChainContextLookupStrategy cannot be null");
- }
+ extends AbstractTrustChainContextLookupFunction<OIDCClientMetadata> {
/** {@inheritDoc} */
@Override @Nullable
- public OIDCClientMetadata apply(@Nullable final ProfileRequestContext input) {
- return Optional.ofNullable(trustChainContextLookupStrategy.apply(input))
- .map(trustChainContext -> trustChainContext.getSelectedTrustChain())
+ public OIDCClientMetadata doApply(@Nonnull final RelyingPartyTrustChainContext trustChainContext) {
+ return Optional.ofNullable(trustChainContext.getSelectedTrustChain())
.map(pair -> pair.getSecond())
.map(clientInfo -> clientInfo.getOIDCMetadata())
.orElse(null);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainTrustAnchorLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainTrustAnchorLookupStrategy.java
new file mode 100644
index 00000000..ae644f2b
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultSelectedTrustChainTrustAnchorLookupStrategy.java
@@ -0,0 +1,41 @@
+/*
+ * 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.navigate;
+
+import java.util.Optional;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
+
+/**
+ * Default strategy for looking up the entity ID of the trust anchor in the selected trust chain. The selected trust
+ * chain is fetched via {@link RelyingPartyTrustChainContext#getSelectedTrustChain()}.
+ */
+public class DefaultSelectedTrustChainTrustAnchorLookupStrategy
+ extends AbstractTrustChainContextLookupFunction<String> {
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ public String doApply(@Nonnull final RelyingPartyTrustChainContext trustChainContext) {
+ return Optional.ofNullable(trustChainContext.getSelectedTrustChain())
+ .map(pair -> pair.getFirst())
+ .filter(list -> list.size() >= 3)
+ .map(list -> list.get(list.size() - 1))
+ .map(entityStatement -> entityStatement.getEntityID().getValue())
+ .orElse(null);
+ }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultTrustChainSelectionStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultTrustChainSelectionStrategy.java
index 1e3b84a1..3bbe1cd5 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultTrustChainSelectionStrategy.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultTrustChainSelectionStrategy.java
@@ -15,14 +15,10 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate;
import java.util.List;
-import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
import org.slf4j.Logger;
import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
@@ -30,7 +26,6 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl.RelyingPartyTrustChainContext;
import net.shibboleth.shared.collection.Pair;
-import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
@@ -38,45 +33,16 @@ import net.shibboleth.shared.primitive.LoggerFactory;
* shortest. The selection must not be included in the list of previously rejected trust chains, obtained via
* {@link RelyingPartyTrustChainContext#getRejectedTrustChains()}.
*/
-public class DefaultTrustChainSelectionStrategy implements
- Function<ProfileRequestContext,Pair<List<EntityStatement>, OIDCClientInformation>> {
+public class DefaultTrustChainSelectionStrategy
+ extends AbstractTrustChainContextLookupFunction<Pair<List<EntityStatement>, OIDCClientInformation>> {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(DefaultTrustChainSelectionStrategy.class);
- /** Strategy used to locate the trust chain context. */
- @Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
-
- /**
- * Constructor.
- */
- public DefaultTrustChainSelectionStrategy() {
- final Function<ProfileRequestContext, RelyingPartyTrustChainContext> tcls =
- new ChildContextLookup<>(RelyingPartyTrustChainContext.class, true).compose(
- new InboundMessageContextLookup());
- assert tcls != null;
- trustChainContextLookupStrategy = tcls;
- }
-
- /**
- * Constructor.
- *
- * @param strategy the strategy used to locate the trust chain context
- */
- public DefaultTrustChainSelectionStrategy(
- @Nonnull final Function<ProfileRequestContext, RelyingPartyTrustChainContext> strategy) {
- trustChainContextLookupStrategy =
- Constraint.isNotNull(strategy, "TrustChainContextLookupStrategy cannot be null");
- }
-
/** {@inheritDoc} */
@Override @Nullable
- public Pair<List<EntityStatement>, OIDCClientInformation> apply(@Nullable final ProfileRequestContext input) {
- final RelyingPartyTrustChainContext trustChainContext = trustChainContextLookupStrategy.apply(input);
- if (trustChainContext == null) {
- log.debug("No trust chain context located");
- return null;
- }
+ public Pair<List<EntityStatement>, OIDCClientInformation> doApply(
+ @Nonnull final RelyingPartyTrustChainContext trustChainContext) {
final List<Pair<List<EntityStatement>, OIDCClientInformation>> policyCompliantChains =
trustChainContext.getPolicyCompliantTrustChains();
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
index f607eec4..c41d1361 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
@@ -14,6 +14,8 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow.oidfed;
+import java.util.List;
+
import org.opensaml.storage.StorageRecord;
import org.opensaml.storage.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -23,6 +25,7 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
+import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatementClaimsSet;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
@@ -78,13 +81,17 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
final ExplicitClientRegistrationResponse parsedResponse =
parseSuccessResponse(result, ExplicitClientRegistrationResponse.class);
final EntityStatement entityStatement = parsedResponse.getEntityStatement();
+ final EntityStatementClaimsSet statementClaims = entityStatement.getClaimsSet();
+ Assert.assertEquals(statementClaims.getAuthorityHints().stream().map(id -> id.getValue()).toList(),
+ List.of(anchorId));
+ Assert.assertEquals(statementClaims.getClaim("trust_anchor"), anchorId);
final OIDCClientInformation clientInfo = entityStatement.getClaimsSet().getRPInformation();
final OIDCClientMetadata metadata = clientInfo.getOIDCMetadata();
final String providedClientId = clientInfo.getID().getValue();
assert providedClientId != null;
assert storageService != null;
- final StorageRecord<String> storageRecord = storageService.read(BaseStorageServiceClientInformationComponent.CONTEXT_NAME,
- providedClientId);
+ final StorageRecord<String> storageRecord =
+ storageService.read(BaseStorageServiceClientInformationComponent.CONTEXT_NAME, providedClientId);
Assert.assertNotNull(storageRecord, "Record with clientId " + providedClientId + " was null");
assert storageRecord != null;
final String record = storageRecord.getValue();
@@ -93,8 +100,8 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
final OIDCClientInformation storedInfo = OIDCClientInformation.parse((JSONObject) parser.parse(record));
Assert.assertEquals(storedInfo.getID(), clientInfo.getID());
Assert.assertEquals(storedInfo.getSecret(), clientInfo.getSecret());
- Assert.assertEquals(storedInfo.getOIDCMetadata().getRedirectionURIStrings(), metadata.getRedirectionURIStrings());
- //Assert.assertEquals(storedInfo.getOIDCMetadata().getRequestObjectURIs(), Set.of(new URI(requestUri)));
+ Assert.assertEquals(storedInfo.getOIDCMetadata().getRedirectionURIStrings(),
+ metadata.getRedirectionURIStrings());
Assert.assertTrue(metadata.getRedirectionURIStrings().contains(redirectUri));
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list