[java-oidfed-common] branch main updated: Move signed-keyset actions from the OP plugin

Codeberg noreply at shibboleth.net
Thu Jun 4 11:33: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-oidfed-common.

View the commit online:
https://codeberg.org/Shibboleth/java-oidfed-common/commit/837a0ab737eb5d924645fed17712544bffb3f22c

The following commit(s) were added to refs/heads/main by this push:
     new 837a0ab  Move signed-keyset actions from the OP plugin
837a0ab is described below

commit 837a0ab737eb5d924645fed17712544bffb3f22c
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Jun 4 14:32:34 2026 +0300

    Move signed-keyset actions from the OP plugin
---
 .../oidfed/profile/impl/BuildSignedKeyset.java     | 142 ++++++++++++++
 .../impl/FormOutboundSignedKeysetResponse.java     | 216 +++++++++++++++++++++
 .../InitializeEntityStatementContextForKeyset.java | 190 ++++++++++++++++++
 3 files changed, 548 insertions(+)

diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/BuildSignedKeyset.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/BuildSignedKeyset.java
new file mode 100644
index 0000000..a253e54
--- /dev/null
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/BuildSignedKeyset.java
@@ -0,0 +1,142 @@
+/*
+ * 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.oidfed.profile.impl;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidfed.profile.config.navigate.EntityStatementLifetimeLookupFunction;
+import net.shibboleth.oidfed.profile.config.navigate.OptionalClaimsLookupStrategiesLookupFunction;
+import net.shibboleth.oidfed.profile.impl.AbstractBuildEntityStatementAction;
+import net.shibboleth.oidfed.profile.impl.EntityStatementContext;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+import org.opensaml.profile.action.ActionSupport;
+
+/**
+ * Action that creates a keyset JWT, and stores it to an {@link EntityStatementContext}.
+ *
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @event {@link EventIds#IO_ERROR}
+ * @event {@link IdPEventIds#INVALID_PROFILE_CONFIG}
+ */
+public class BuildSignedKeyset extends AbstractBuildEntityStatementAction {
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(BuildSignedKeyset.class);
+
+    /** Strategy used to obtain the entity statement lifetime. */
+    @Nonnull private Function<ProfileRequestContext,Duration> entityStatementLifetimeLookupStrategy;
+
+    /** Strategy used to locate strategies for optional claims. */
+    @Nonnull private Function<ProfileRequestContext,Map<String, Function<ProfileRequestContext,Object>>>
+        optionalClaimsLookupStrategiesLookupStrategy;
+
+    /** Constructor. */
+    public BuildSignedKeyset() {
+        entityStatementLifetimeLookupStrategy = new EntityStatementLifetimeLookupFunction();
+        optionalClaimsLookupStrategiesLookupStrategy = new OptionalClaimsLookupStrategiesLookupFunction();
+    }
+
+    /**
+     * Set the strategy used to obtain the entity statement lifetime.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setEntityStatementLifetimeLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        checkSetterPreconditions();
+        
+        entityStatementLifetimeLookupStrategy =
+                Constraint.isNotNull(strategy, "Entity statement lifetime lookup strategy cannot be null");
+    }
+
+    /**
+     * Set the strategy used to locate strategies for optional claims.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setOptionalClaimsLookupStrategiesLookupStrategy(@Nonnull final
+            Function<ProfileRequestContext, Map<String,Function<ProfileRequestContext,Object>>> strategy) {
+        checkSetterPreconditions();
+
+        optionalClaimsLookupStrategiesLookupStrategy =
+                Constraint.isNotNull(strategy, "Optional claims lookup strategies lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean populateClaimsSetBuilder(@Nonnull final JWTClaimsSet.Builder builder,
+            @Nonnull final ProfileRequestContext profileRequestContext) {
+
+        final Duration lifetime = entityStatementLifetimeLookupStrategy.apply(profileRequestContext);
+        if (lifetime == null || Duration.ZERO.equals(lifetime)) {
+            log.debug("{} No lifetime supplied for entity statement", getLogPrefix());
+        } else {
+            final Instant now = Instant.now();
+            final Instant dateExp = now.plus(lifetime);
+            assert dateExp != null;
+
+            log.debug("{} Set expiration time of entity statement into {}", getLogPrefix(), dateExp);
+            builder.expirationTime(Date.from(dateExp));
+        }
+        
+        final JWKSet jwks = entityStatementCtx.getKeys();
+        if (jwks == null || jwks.isEmpty()) {
+            log.error("{} No credentials to publish resolved for signed keyset entity statement", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
+            
+        }
+
+        log.trace("{} Resolved jwks to publish: {}", getLogPrefix(), jwks);
+        
+        builder.claim("keys", jwks.toJSONObject(true).get("keys"));
+
+        final Map<String, Function<ProfileRequestContext, Object>> optionalClaimsLookupStrategies =
+                optionalClaimsLookupStrategiesLookupStrategy.apply(profileRequestContext);
+        if (optionalClaimsLookupStrategies != null) {
+            for (final String claim : optionalClaimsLookupStrategies.keySet()) {
+                log.trace("{} Looking up the value for clain {}", getLogPrefix(), claim);
+                final Function<ProfileRequestContext,Object> lookup = optionalClaimsLookupStrategies.get(claim);
+                final Object value = lookup.apply(profileRequestContext);
+                if (value != null) {
+                    log.debug("{} Resolved value {} for clain {}", getLogPrefix(), value, claim);
+                    builder.claim(claim, value);
+                } else {
+                    log.debug("{} No value resolved for clain {}", getLogPrefix(), claim);
+                }
+            }
+        }
+
+       return true;
+   }
+
+}
\ No newline at end of file
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/FormOutboundSignedKeysetResponse.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/FormOutboundSignedKeysetResponse.java
new file mode 100644
index 0000000..d1fb3b6
--- /dev/null
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/FormOutboundSignedKeysetResponse.java
@@ -0,0 +1,216 @@
+/*
+ * 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.oidfed.profile.impl;
+
+import java.time.Duration;
+import java.time.Instant;
+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.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
+import org.slf4j.Logger;
+
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.Response;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.oidc.metadata.cache.MetadataCache;
+import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
+import net.shibboleth.oidfed.messaging.impl.SignedKeysetResponse;
+import net.shibboleth.oidfed.metadata.cache.ResponseContainerExpirationCriterion;
+import net.shibboleth.oidfed.metadata.cache.local.NimbusResponseContainer;
+import net.shibboleth.oidfed.metadata.cache.local.NimbusResponseCriterion;
+import net.shibboleth.oidfed.profile.config.navigate.CachedSuccessResponseLifetimeLookupFunction;
+import net.shibboleth.oidfed.profile.impl.EntityStatementContext;
+import net.shibboleth.oidfed.profile.impl.RelyingPartyCachedMessageContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * This action builds a response for the OpenID federation configuration request. The response contains an
+ * {@link SignedJWT} obtained from {@link EntityStatementContext#getJWT()}.
+ */
+public class FormOutboundSignedKeysetResponse extends AbstractProfileAction {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(FormOutboundSignedKeysetResponse.class);
+
+    /** Metadata cache for cached response containers. */
+    @NonnullAfterInit private MetadataCache<NimbusResponseContainer> responseCache;
+
+    /** Strategy used to locate the cached message context. */
+    @Nonnull
+    private Function<ProfileRequestContext, RelyingPartyCachedMessageContext> cachedMessageContextLookupStrategy;
+
+    /** Strategy used to locate the subcontext to hold the statement. */
+    @Nonnull private Function<ProfileRequestContext,EntityStatementContext> entityStatementContextLookupStrategy;
+
+    /** Strategy used to locate the lifetime for the cached response record. */
+    @Nonnull private Function<ProfileRequestContext,Duration> cachedResponseLifetimeLookupStrategy;
+
+    /** JWT used to build entity statement. */
+    @Nullable private SignedJWT jwt;
+
+    /** The resolve entity context to operate on. */
+    @NonnullBeforeExec private RelyingPartyCachedMessageContext cachedMessageContext;
+
+    /**
+     * Constructor.
+     */
+    public FormOutboundSignedKeysetResponse() {
+        final Function<ProfileRequestContext,EntityStatementContext> escls =
+                new ChildContextLookup<>(EntityStatementContext.class).compose(
+                        new OutboundMessageContextLookup());
+        assert escls != null;
+        entityStatementContextLookupStrategy = escls;
+        cachedMessageContextLookupStrategy = new ChildContextLookup<>(RelyingPartyCachedMessageContext.class);
+        cachedResponseLifetimeLookupStrategy = new CachedSuccessResponseLifetimeLookupFunction();
+    }
+
+    /**
+     * Set the strategy used to locate the subcontext to hold the statement
+     * 
+     * @param strategy What to set.
+     */
+    public void setEntityStatementContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,EntityStatementContext> strategy) {
+        checkSetterPreconditions();
+        entityStatementContextLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null!");
+    }
+
+    /**
+     * Set the strategy used to locate the cached message context
+     * 
+     * @param strategy What to set.
+     */
+    public void setCachedMessageContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,RelyingPartyCachedMessageContext> strategy) {
+        checkSetterPreconditions();
+        cachedMessageContextLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null!");
+    }
+
+    /**
+     * Set the metadata cache for cached response containers.
+     * 
+     * @param cache What to set.
+     */
+    public void setResponseCache(@Nonnull final MetadataCache<NimbusResponseContainer> cache) {
+        checkSetterPreconditions();
+        responseCache = Constraint.isNotNull(cache, "Response metadata cache cannot be null");
+    }
+
+    /**
+     * Set the strategy used to locate the lifetime for the cached response record.
+     * 
+     * @param strategy What to set.
+     */
+    public void setCachedResponseLifetimeLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, Duration> strategy) {
+        checkSetterPreconditions();
+        cachedResponseLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+
+        if (responseCache == null) {
+            throw new ComponentInitializationException("Response metadata cache cannot be null");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        cachedMessageContext = cachedMessageContextLookupStrategy.apply(profileRequestContext);
+        if (cachedMessageContext == null) {
+            log.error("{} Could not resolve cached message context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        final Response cachedResponse = cachedMessageContext.getCachedResponse();
+        if (cachedResponse != null) {
+            log.debug("{} Cached response found, storing in to the outbound message context", getLogPrefix());
+            profileRequestContext.ensureOutboundMessageContext().setMessage(cachedResponse);
+            return;
+        }
+        log.debug("{} No cached response found, resolving the response JWT from the context", getLogPrefix());
+        final EntityStatementContext entityStatementContext =
+                entityStatementContextLookupStrategy.apply(profileRequestContext);
+        if (entityStatementContext == null) {
+            log.error("{} Could not resolve entity statement context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+        if (entityStatementContext.getJWT() instanceof SignedJWT signedJwt) {
+            jwt = signedJwt;
+        } else {
+            log.error("{} No signed JWT found from the entity statement context", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+
+        assert jwt != null;
+        final SignedKeysetResponse response = new SignedKeysetResponse(jwt);
+        final NimbusResponseCriterion responseCriterion = new NimbusResponseCriterion(response);
+        final Duration lifetime = cachedResponseLifetimeLookupStrategy.apply(profileRequestContext);
+        if (lifetime == null) {
+            log.error("{} Could not resolve lifetime for the cached response record", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+        final Instant expiration = Instant.now().plus(lifetime);
+        assert expiration != null;
+        final ResponseContainerExpirationCriterion expirationCriterion =
+                new ResponseContainerExpirationCriterion(expiration);
+        final CriteriaSet criteria = new CriteriaSet(responseCriterion, expirationCriterion);
+        try {
+            final List<NimbusResponseContainer> result = responseCache.get(criteria);
+            if (result.size() != 1) {
+                log.error("{} Unexpected result (size={}) when storing response record into the metadata cache",
+                        getLogPrefix(), result.size());
+            } else {
+                log.debug("{} Response stored into the cache", getLogPrefix());
+            }
+        } catch (final MetadataCacheException e) {
+            log.error("{} Could not store the response record into tht metadata cache", getLogPrefix(), e);
+        }
+
+        profileRequestContext.ensureOutboundMessageContext().setMessage(response);
+    }
+}
\ No newline at end of file
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/InitializeEntityStatementContextForKeyset.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/InitializeEntityStatementContextForKeyset.java
new file mode 100644
index 0000000..48e8957
--- /dev/null
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/profile/impl/InitializeEntityStatementContextForKeyset.java
@@ -0,0 +1,190 @@
+/*
+ * 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.oidfed.profile.impl;
+
+import java.util.Collections;
+import java.util.List;
+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.OutboundMessageContextLookup;
+import org.opensaml.security.config.SecurityConfiguration;
+import org.opensaml.security.credential.Credential;
+import org.slf4j.Logger;
+
+import com.nimbusds.jose.jwk.JWKSet;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.profile.config.JSONSecurityConfiguration;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
+import net.shibboleth.oidfed.profile.impl.EntityStatementContext;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+
+/**
+ * Action that creates and initializes the {@link EntityStatementContext}.
+ *
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @event {@link EventIds#IO_ERROR}
+ */
+public class InitializeEntityStatementContextForKeyset extends AbstractProfileAction {
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(InitializeEntityStatementContextForKeyset.class);
+
+    /** Strategy used to create the subcontext to hold the statement. */
+    @Nonnull private Function<ProfileRequestContext,EntityStatementContext> entityStatementContextCreationStrategy;
+
+    /**
+     * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
+     */
+    @Nonnull private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
+    
+    /**
+     * Strategy used to locate the list of credentials to publish.
+     */
+    @Nonnull private Function<JSONSecurityConfiguration, List<Credential>> credentialsToPublishLookupStrategy;
+
+    /** Security configuration we look for keys to publish. */
+    @Nullable private JSONSecurityConfiguration secConfiguration;
+
+    /** Entity statement context. */
+    @NonnullBeforeExec private EntityStatementContext entityStatementCtx;
+
+    /** Constructor. */
+    public InitializeEntityStatementContextForKeyset() {
+        final Function<ProfileRequestContext,EntityStatementContext> esccs =
+                new ChildContextLookup<>(EntityStatementContext.class, true).compose(
+                        new OutboundMessageContextLookup());
+        assert esccs != null;
+        entityStatementContextCreationStrategy = esccs; 
+        relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+        credentialsToPublishLookupStrategy = secConfig -> Collections.emptyList();
+    }
+
+    /**
+     * Set the strategy used to create the {@link EntityStatementContext} to use.
+     * 
+     * @param strategy creation strategy
+     */
+    public void setEntityStatementContextCreationStrategy(
+            @Nonnull final Function<ProfileRequestContext,EntityStatementContext> strategy) {
+        checkSetterPreconditions();
+        
+        entityStatementContextCreationStrategy =
+                Constraint.isNotNull(strategy, "EntityStatementContext creation strategy cannot be null");
+    }
+
+    /**
+     * Set the strategy used to locate the {@link RelyingPartyContext} associated with a given
+     * {@link ProfileRequestContext}.
+     * 
+     * @param strategy strategy used to locate the {@link RelyingPartyContext} associated with a given
+     *            {@link ProfileRequestContext}
+     */
+    public void setRelyingPartyContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, RelyingPartyContext> strategy) {
+        checkSetterPreconditions();
+
+        relyingPartyContextLookupStrategy =
+                Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
+    }
+    
+    /**
+     * Set the strategy used to locate the credentials to publish at the KeySet endpoint.
+     * 
+     * @param strategy the strategy.
+     */
+    public void setCredentialsToPublishLookupStrategy(
+            @Nonnull final Function<JSONSecurityConfiguration, List<Credential>> strategy) {
+        checkSetterPreconditions();
+
+        credentialsToPublishLookupStrategy = Constraint.isNotNull(strategy,
+                "credentialsToPublishLookupStrategy can not be null");
+    }
+
+ // Checkstyle: CyclomaticComplexity|MethodLength OFF
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        entityStatementCtx = entityStatementContextCreationStrategy.apply(profileRequestContext);
+        if (entityStatementCtx == null) {
+            log.error("{} Unable to create EntityStatementContext", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+
+        final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+        if (rpCtx == null) {
+            log.debug("{} No relying party context associated with this profile request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        }
+
+        final ProfileConfiguration profileConfig = rpCtx.getProfileConfig();
+        if (profileConfig == null) {
+            log.debug("{} No profile configuration associated with this profile request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        }
+
+        final SecurityConfiguration securityConfig =
+                profileConfig.getSecurityConfiguration(profileRequestContext);
+        
+        if (!(securityConfig instanceof JSONSecurityConfiguration)) {
+            log.debug("{} No security configuration associated with the profile configuration of the profile request",
+                    getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
+            return false;
+        }
+        
+        secConfiguration = (JSONSecurityConfiguration) securityConfig;
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+        final List<Credential> credentialsToPublish = credentialsToPublishLookupStrategy.apply(secConfiguration);
+        if (credentialsToPublish == null || credentialsToPublish.isEmpty()) {
+            log.error("{} No credentials to publish resolved for signed keyset entity statement", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return;
+        }
+
+        final JWKSet jwks = new JWKSet(credentialsToPublish.stream()
+                .map(credential -> CredentialConversionUtil.credentialToKey(credential))
+                .toList());
+        log.trace("{} Resolved jwks to set in the contet: {}", getLogPrefix(), jwks);
+        entityStatementCtx.setKeys(jwks);
+    }
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list