[java-idp-oidc] branch main updated: JOIDC-258 - Move generic parts of the dynamic registration flow into an abstract flow

Henri Mikkonen henri.mikkonen at iki.fi
Wed Sep 10 12:38:45 UTC 2025


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch main
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=ab7eadf179a6de718db4676ba93679257a88554f

The following commit(s) were added to refs/heads/main by this push:
     new ab7eadf1 JOIDC-258 - Move generic parts of the dynamic registration flow into an abstract flow
ab7eadf1 is described below

commit ab7eadf179a6de718db4676ba93679257a88554f
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Sep 10 15:38:28 2025 +0300

    JOIDC-258 - Move generic parts of the dynamic registration flow into an abstract flow
    
    https://shibboleth.atlassian.net/browse/JOIDC-258
    
    Initial implementation of the oidc/abstract-register flow
    - Extend OIDCClientRegistrationResponseContext with clientInformation
    - Refactor StoreClientInformation to use configurable strategies
      - DefaultClientInformationLookupFunction and DefaultClientInformationReplacementCondition
    - Refactor CheckRedirectURIs to use configurable strategy for fetching requested metadata
      - DefaultRequestedMetadataLookupFunction
    - Refactor BuildClientInformation to not build the registration response message
      - FormOutboundClientInformationResponseMessage builds the response message
---
 .../OIDCClientRegistrationResponseContext.java     |  70 +++++++----
 .../DefaultClientInformationLookupFunction.java    |  44 +++++++
 .../DefaultRequestedMetadataLookupFunction.java    |  46 ++++++++
 .../impl/AbstractOIDCClientRegistrationAction.java | 101 ++++++++++++++++
 .../op/profile/impl/BuildClientInformation.java    |  71 +----------
 .../oidc/op/profile/impl/CheckRedirectURIs.java    |  54 +++++----
 ...rmOutboundClientInformationResponseMessage.java |  52 ++++++++
 .../op/profile/impl/StoreClientInformation.java    | 107 ++++++-----------
 ...faultClientInformationReplacementCondition.java |  60 ++++++++++
 .../oidc-abstract-api-info-flow.xml                |   7 +-
 .../oidc-abstract-register-beans.xml               | 131 +++++++++++++++++++++
 .../oidc-abstract-register-flow.xml}               |  41 ++-----
 .../idp/flows/oidc/abstract/oidc-abstract-flow.xml |   5 +-
 .../idp/flows/oidc/register/register-beans.xml     | 101 ++--------------
 .../idp/flows/oidc/register/register-flow.xml      |  54 +--------
 .../profile/impl/BuildClientInformationTest.java   |  19 +--
 .../op/profile/impl/CheckRedirectUrisTest.java     |   2 +-
 17 files changed, 593 insertions(+), 372 deletions(-)

diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCClientRegistrationResponseContext.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCClientRegistrationResponseContext.java
index 5ab7f7de..d7cb9ba8 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCClientRegistrationResponseContext.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCClientRegistrationResponseContext.java
@@ -16,8 +16,11 @@ package net.shibboleth.idp.plugin.oidc.op.messaging.context;
 
 import java.time.Instant;
 
+import javax.annotation.Nullable;
+
 import org.opensaml.messaging.context.BaseContext;
 
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 
 /**
@@ -27,31 +30,34 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 public class OIDCClientRegistrationResponseContext extends BaseContext  {
 
     /** Mandatory Unique Client Identifier. */
-    private String clientId;
+    @Nullable private String clientId;
     
     /** Optional client secret. */
-    private String clientSecret;
+    @Nullable private String clientSecret;
     
     /** Optional registration access token. */
-    private String regAccessToken;
+    @Nullable private String regAccessToken;
     
     /** Optional location of the client configuration endpoint. */
-    private String regClientUri;
+    @Nullable private String regClientUri;
     
     /** Optional time at which the client identifier was issued. */
-    private Instant clientIdIssuedAt;
+    @Nullable private Instant clientIdIssuedAt;
     
     /** Time at which the client secret will expire or 0 if it will not expire. Required if the secret was issued. */
-    private Instant clientSecretExpiresAt;
+    @Nullable private Instant clientSecretExpiresAt;
     
     /** The metadata for the client: the attributes supported by the OP must be included. */
-    private OIDCClientMetadata clientMetadata;
+    @Nullable private OIDCClientMetadata clientMetadata;
+
+    /** The client information object carrying client ID, secret and metadata. */
+    @Nullable private OIDCClientInformation clientInformation;
 
     /**
      * Get the client identifier.
      * @return The client identifier.
      */
-    public String getClientId() {
+    @Nullable public String getClientId() {
         return clientId;
     }
 
@@ -59,7 +65,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the client identifier.
      * @param id The client identifier.
      */
-    public void setClientId(final String id) {
+    public void setClientId(@Nullable final String id) {
         this.clientId = id;
     }
 
@@ -67,7 +73,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the client secret.
      * @return The client secret.
      */
-    public String getClientSecret() {
+    @Nullable public String getClientSecret() {
         return clientSecret;
     }
 
@@ -75,7 +81,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the client secret.
      * @param secret The client secret.
      */
-    public void setClientSecret(final String secret) {
+    public void setClientSecret(@Nullable final String secret) {
         this.clientSecret = secret;
     }
 
@@ -83,7 +89,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the registration access token.
      * @return The registration access token.
      */
-    public String getRegAccessToken() {
+    @Nullable public String getRegAccessToken() {
         return regAccessToken;
     }
 
@@ -91,7 +97,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the registration access token.
      * @param accessToken The registration access token.
      */
-    public void setRegAccessToken(final String accessToken) {
+    public void setRegAccessToken(@Nullable final String accessToken) {
         this.regAccessToken = accessToken;
     }
 
@@ -99,7 +105,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the location of the client configuration endpoint.
      * @return The location of the client configuration endpoint.
      */
-    public String getRegClientUri() {
+    @Nullable public String getRegClientUri() {
         return regClientUri;
     }
 
@@ -107,7 +113,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the location of the client configuration endpoint.
      * @param clientUri The location of the client configuration endpoint.
      */
-    public void setRegClientUri(final String clientUri) {
+    public void setRegClientUri(@Nullable final String clientUri) {
         this.regClientUri = clientUri;
     }
 
@@ -115,7 +121,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the time at which the client identifier was issued.
      * @return The time at which the client identifier was issued.
      */
-    public Instant getClientIdIssuedAt() {
+    @Nullable public Instant getClientIdIssuedAt() {
         return clientIdIssuedAt;
     }
 
@@ -123,7 +129,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the time at which the client identifier was issued.
      * @param idIssuedAt The time at which the client identifier was issued.
      */
-    public void setClientIdIssuedAt(final Instant idIssuedAt) {
+    public void setClientIdIssuedAt(@Nullable final Instant idIssuedAt) {
         this.clientIdIssuedAt = idIssuedAt;
     }
 
@@ -131,7 +137,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the time at which the client secret will expire.
      * @return The time at which the client secret will expire.
      */
-    public Instant getClientSecretExpiresAt() {
+    @Nullable public Instant getClientSecretExpiresAt() {
         return clientSecretExpiresAt;
     }
 
@@ -139,7 +145,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the time at which the client secret will expire.
      * @param secretExpiresAt The time at which the client secret will expire.
      */
-    public void setClientSecretExpiresAt(final Instant secretExpiresAt) {
+    public void setClientSecretExpiresAt(@Nullable final Instant secretExpiresAt) {
         this.clientSecretExpiresAt = secretExpiresAt;
     }
 
@@ -147,7 +153,7 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Get the metadata for the client: the attributes supported by the OP must be included.
      * @return The metadata for the client: the attributes supported by the OP must be included.
      */
-    public OIDCClientMetadata getClientMetadata() {
+    @Nullable public OIDCClientMetadata getClientMetadata() {
         return clientMetadata;
     }
     
@@ -155,7 +161,29 @@ public class OIDCClientRegistrationResponseContext extends BaseContext  {
      * Set the metadata for the client: the attributes supported by the OP must be included.
      * @param metadata The metadata for the client: the attributes supported by the OP must be included.
      */
-    public void setClientMetadata(final OIDCClientMetadata metadata) {
+    public void setClientMetadata(@Nullable final OIDCClientMetadata metadata) {
         this.clientMetadata = metadata;
     }
+
+    /**
+     * Set the client information object carrying client ID, secret and metadata.
+     * 
+     * @since 4.4.0
+     * 
+     * @param information The client information object carrying client ID, secret and metadata.
+     */
+    public void setClientInformation(@Nullable final OIDCClientInformation information) {
+        clientInformation = information;
+    }
+
+    /**
+     * Get the client information object carrying client ID, secret and metadata.
+     * 
+     * @since 443.0
+     * 
+     * @return The client information object carrying client ID, secret and metadata.
+     */
+    @Nullable public OIDCClientInformation getClientInformation() {
+        return clientInformation;
+    }
 }
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultClientInformationLookupFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultClientInformationLookupFunction.java
new file mode 100644
index 00000000..ddca2d95
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultClientInformationLookupFunction.java
@@ -0,0 +1,44 @@
+/*
+ * 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.messaging.context.navigate;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
+
+/**
+ * Default lookup function for fetching {@link OIDCClientInformation} from {@link OIDCClientRegistrationResponseContext}
+ * located under outbound message context.
+ * 
+ * @since 4.4.0
+ */
+public class DefaultClientInformationLookupFunction implements Function<ProfileRequestContext, OIDCClientInformation> {
+
+    /** {@inheritDoc} */
+    @Nullable public OIDCClientInformation apply(@Nullable final ProfileRequestContext input) {
+        return Optional.ofNullable(input)
+                .map(profileRequestContext -> profileRequestContext.getOutboundMessageContext())
+                .map(messageContext -> messageContext.getSubcontext(OIDCClientRegistrationResponseContext.class))
+                .map(oidcResponseContext -> oidcResponseContext.getClientInformation())
+                .orElse(null);
+    }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultRequestedMetadataLookupFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultRequestedMetadataLookupFunction.java
new file mode 100644
index 00000000..6debc0f0
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/navigate/DefaultRequestedMetadataLookupFunction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.messaging.context.navigate;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientRegistrationRequest;
+
+/**
+ * Default lookup function for fetching requested {@link OIDCClientMetadata} from the inbound dynamic client
+ * registration request message ({@link OIDCClientRegistrationRequest}).
+ * 
+ * @since 4.4.0
+ */
+public class DefaultRequestedMetadataLookupFunction implements Function<ProfileRequestContext, OIDCClientMetadata> {
+
+    /** {@inheritDoc} */
+    @Nullable public OIDCClientMetadata apply(@Nullable final ProfileRequestContext input) {
+        return Optional.ofNullable(input)
+                .map(profileRequestContext -> profileRequestContext.getInboundMessageContext())
+                .map(messageContext -> messageContext.getMessage())
+                .filter(OIDCClientRegistrationRequest.class::isInstance)
+                .map(OIDCClientRegistrationRequest.class::cast)
+                .map(request -> request.getOIDCClientMetadata())
+                .orElse(null);
+                
+    }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractOIDCClientRegistrationAction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractOIDCClientRegistrationAction.java
new file mode 100644
index 00000000..4bfab282
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractOIDCClientRegistrationAction.java
@@ -0,0 +1,101 @@
+/*
+ * 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.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+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 net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Abstract action for dynamic client registration actions dealing with {@link OIDCClientRegistrationResponseContext}.
+ * 
+ * @since 4.4.0
+ */
+public abstract class AbstractOIDCClientRegistrationAction extends AbstractProfileAction {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCClientRegistrationAction.class);
+
+    /** The strategy used to locate the {@link OIDCClientRegistrationResponseContext}. */
+    @Nonnull
+    private Function<ProfileRequestContext,OIDCClientRegistrationResponseContext> oidcResponseContextLookupStrategy;
+
+    /** The {@link OIDCClientRegistrationResponseContext} to operate on. */
+    @NonnullBeforeExec private OIDCClientRegistrationResponseContext oidcResponseContext;
+    
+    /** Constructor. */
+    public AbstractOIDCClientRegistrationAction() {
+        final Function<ProfileRequestContext, OIDCClientRegistrationResponseContext> ocrrls =
+                new ChildContextLookup<>(OIDCClientRegistrationResponseContext.class)
+                    .compose(new OutboundMessageContextLookup());
+        assert ocrrls != null;
+        oidcResponseContextLookupStrategy = ocrrls;
+    }
+
+    /**
+     * Set the strategy used to locate the {@link OIDCClientRegistrationResponseContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setOidcResponseContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,OIDCClientRegistrationResponseContext> strategy) {
+        checkSetterPreconditions();
+        oidcResponseContextLookupStrategy = Constraint.isNotNull(strategy, 
+                "The output OIDCClientRegistrationResponseContext lookup strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        oidcResponseContext = oidcResponseContextLookupStrategy.apply(profileRequestContext);
+        if (oidcResponseContext == null) {
+            log.debug("{} No OIDCClientRegistrationResponseContext associated with this profile request",
+                    getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+            return false;                        
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the {@link OIDCClientRegistrationResponseContext}. Cannot be null after
+     * {@link #doPreExecute(ProfileRequestContext)} has returned true.
+     * 
+     * @return registration context
+     */
+    @Nonnull protected OIDCClientRegistrationResponseContext getRegistrationContext() {
+        checkComponentActive();
+        return oidcResponseContext;
+    }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformation.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformation.java
index bf5a948a..8bdfad3f 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformation.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformation.java
@@ -16,12 +16,9 @@ package net.shibboleth.idp.plugin.oidc.op.profile.impl;
 
 import java.time.Instant;
 import java.util.Date;
-import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 
-import org.opensaml.messaging.context.MessageContext;
-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;
@@ -32,12 +29,9 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
 import com.nimbusds.oauth2.sdk.client.ClientInformationResponse;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformationResponse;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 
 import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
-import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -45,70 +39,15 @@ import net.shibboleth.shared.primitive.StringSupport;
  * An action that uses the information from {@link OIDCClientRegistrationResponseContext} attached to the message
  * context for creating a new {@link ClientInformationResponse}. It will be set as the outbound message.
  */
-public class BuildClientInformation extends AbstractProfileAction {
+public class BuildClientInformation extends AbstractOIDCClientRegistrationAction {
 
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(BuildClientInformation.class);
     
-    /**
-     * Strategy used to locate the {@link OIDCClientRegistrationResponseContext} associated with a given 
-     * {@link MessageContext}.
-     */
-    @Nonnull private Function<MessageContext,OIDCClientRegistrationResponseContext> oidcResponseContextLookupStrategy;
-
-    /** The {@link MessageContext} to operate on. */
-    private MessageContext messageContext;
-
-    /** The {@link OIDCClientRegistrationResponseContext} to operate on. */
-    private OIDCClientRegistrationResponseContext oidcResponseContext;
-
-    /** Constructor. */
-    public BuildClientInformation() {
-        oidcResponseContextLookupStrategy = new ChildContextLookup<>(OIDCClientRegistrationResponseContext.class);
-    }
-    
-    /**
-     * Set the strategy used to locate the {@link OIDCClientRegistrationResponseContext} associated with a given
-     * {@link MessageContext}.
-     * 
-     * @param strategy strategy used to locate the {@link OIDCClientRegistrationResponseContext} associated with a 
-     *         given {@link MessageContext}
-     */
-    public void setOidcResponseContextLookupStrategy(
-            @Nonnull final Function<MessageContext,OIDCClientRegistrationResponseContext> strategy) {
-        ifInitializedThrowUnmodifiabledComponentException();
-        
-        oidcResponseContextLookupStrategy = Constraint.isNotNull(strategy,
-                "OIDCClientRegistrationResponseContext lookup strategy cannot be null");
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        if (!super.doPreExecute(profileRequestContext)) {
-            return false;
-        }
-
-        messageContext = profileRequestContext.getOutboundMessageContext();
-        if (messageContext == null) {
-            log.error("{} No message context found", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
-            return false;
-        }
-
-        oidcResponseContext = oidcResponseContextLookupStrategy.apply(messageContext);
-        if (oidcResponseContext == null) {
-            log.error("{} No OIDC response context found", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
-            return false;
-        }
-
-        return true;
-    }
-
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        final OIDCClientRegistrationResponseContext oidcResponseContext = getRegistrationContext();
 
         final String id = oidcResponseContext.getClientId();
         if (StringSupport.trimOrNull(id) == null) {
@@ -150,9 +89,7 @@ public class BuildClientInformation extends AbstractProfileAction {
         
         final OIDCClientInformation clientInformation = new OIDCClientInformation(clientId, new Date(), 
                 metadata, clientSecret);
-        final OIDCClientInformationResponse response = new OIDCClientInformationResponse(clientInformation, true);
-        messageContext.setMessage(response);
-        log.info("{} Client information successfully added to the outbound context", getLogPrefix());
-        
+        oidcResponseContext.setClientInformation(clientInformation);
+        log.info("{} Client information successfully populated to the response context", getLogPrefix());
     }    
 }
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectURIs.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectURIs.java
index 54fa8ca1..f7bfc9bf 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectURIs.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectURIs.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -44,11 +45,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.oauth2.sdk.GrantType;
 import com.nimbusds.openid.connect.sdk.rp.ApplicationType;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientRegistrationRequest;
 
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultRequestedMetadataLookupFunction;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.oidc.profile.core.OidcEventIds;
 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;
@@ -73,9 +75,6 @@ public class CheckRedirectURIs extends AbstractProfileAction {
     @Nonnull
     private final Logger log = LoggerFactory.getLogger(CheckRedirectURIs.class);
     
-    /** The OIDCClientRegistrationRequest to check redirect URIs from. */
-    @Nullable private OIDCClientRegistrationRequest request;
-
     /** The {@link HttpClient} to use. */
     @NonnullAfterInit private HttpClient httpClient;
     
@@ -85,9 +84,16 @@ public class CheckRedirectURIs extends AbstractProfileAction {
     /** JSON object mapper. */
     @NonnullAfterInit private ObjectMapper objectMapper;
 
+    /** Lookup strategy for requested metadata */
+    @Nonnull private Function<ProfileRequestContext, OIDCClientMetadata> requestMetadataLookupStrategy;
+
+    /** Requested metadata to operate on. */
+    @NonnullBeforeExec private OIDCClientMetadata metadata;
+
     /** Constructor. */
     public CheckRedirectURIs() {
         super();
+        requestMetadataLookupStrategy = new DefaultRequestedMetadataLookupFunction();
     }
     
     /**
@@ -96,8 +102,7 @@ public class CheckRedirectURIs extends AbstractProfileAction {
      * @param client client to use
      */
     public void setHttpClient(@Nonnull final HttpClient client) {
-        ifInitializedThrowUnmodifiabledComponentException();
-        ifDestroyedThrowDestroyedComponentException();
+        checkSetterPreconditions();
 
         httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
     }
@@ -108,8 +113,7 @@ public class CheckRedirectURIs extends AbstractProfileAction {
      * @param params the new client security parameters
      */
     public void setHttpClientSecurityParameters(@Nullable final HttpClientSecurityParameters params) {
-        ifInitializedThrowUnmodifiabledComponentException();
-        ifDestroyedThrowDestroyedComponentException();
+        checkSetterPreconditions();
 
         httpClientSecurityParameters = params;
     }
@@ -120,11 +124,25 @@ public class CheckRedirectURIs extends AbstractProfileAction {
      * @param mapper object mapper
      */
     public void setObjectMapper(@Nonnull final ObjectMapper mapper) {
-        ifInitializedThrowUnmodifiabledComponentException();
+        checkSetterPreconditions();
 
         objectMapper = Constraint.isNotNull(mapper, "Object mapper cannot be null");
     }
 
+    /**
+     * Set the lookup strategy for requested metadata.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 4.4.0
+     */
+    public void setRequestMetadataLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, OIDCClientMetadata> strategy) {
+        checkSetterPreconditions();
+
+        requestMetadataLookupStrategy =
+                Constraint.isNotNull(strategy, "Request metadata lookup strategy cannot be null");
+    }
     /** {@inheritDoc} */
     public void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
@@ -150,13 +168,12 @@ public class CheckRedirectURIs extends AbstractProfileAction {
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
             return false;            
         }
-        final Object message = profileRequestContext.ensureInboundMessageContext().getMessage();
-        if (message == null || !(message instanceof OIDCClientRegistrationRequest)) {
-            log.debug("{} No inbound message associated with this profile request", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
-            return false;                        
+        metadata = requestMetadataLookupStrategy.apply(profileRequestContext);
+        if (metadata == null) {
+            log.warn("{} No client metadata found in the request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return false;
         }
-        request = (OIDCClientRegistrationRequest) message;
         return true;
     }
 
@@ -165,13 +182,6 @@ public class CheckRedirectURIs extends AbstractProfileAction {
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        assert request != null;
-        final OIDCClientMetadata metadata = request.getOIDCClientMetadata();
-        if (metadata == null) {
-            log.warn("{} No client metadata found in the request", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
-            return;
-        }
         final Set<URI> redirectURIs = metadata.getRedirectionURIs();
         if (redirectURIs == null || redirectURIs.isEmpty()) {
             log.warn("{} No redirection URIs found in the request", getLogPrefix());
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundClientInformationResponseMessage.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundClientInformationResponseMessage.java
new file mode 100644
index 00000000..088501c2
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/FormOutboundClientInformationResponseMessage.java
@@ -0,0 +1,52 @@
+/*
+ * 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.profile.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformationResponse;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Action that forms outbound dynamic client registration response.
+ * 
+ * @since 4.4.0
+ */
+public class FormOutboundClientInformationResponseMessage extends AbstractOIDCClientRegistrationAction {
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(FormOutboundClientInformationResponseMessage.class);
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        final OIDCClientInformation clientInformation = getRegistrationContext().getClientInformation();
+        if (clientInformation == null) {
+            log.error("{} Could not find client information from context data", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+        final OIDCClientInformationResponse response = new OIDCClientInformationResponse(clientInformation, true);
+        profileRequestContext.ensureOutboundMessageContext().setMessage(response);
+        log.info("{} Client information successfully added to the outbound context", getLogPrefix());
+    }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/StoreClientInformation.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/StoreClientInformation.java
index eef8bfaa..d41f0eec 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/StoreClientInformation.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/StoreClientInformation.java
@@ -17,6 +17,7 @@ package net.shibboleth.idp.plugin.oidc.op.profile.impl;
 import java.time.Duration;
 import java.time.Instant;
 import java.util.function.Function;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -28,12 +29,10 @@ import org.slf4j.Logger;
 
 import com.nimbusds.oauth2.sdk.client.ClientInformation;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformationResponse;
 
 import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationTokenClaimsContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCClientRegistrationTokenClaimsContextLookupFunction;
-import net.shibboleth.idp.plugin.oidc.op.token.support.RegistrationClaimsSet;
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.DefaultClientInformationLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultClientInformationReplacementCondition;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.oidc.metadata.ClientInformationManager;
 import net.shibboleth.oidc.metadata.ClientInformationManagerException;
@@ -52,24 +51,21 @@ public class StoreClientInformation extends AbstractProfileAction {
     @Nonnull private final Logger log = LoggerFactory.getLogger(StoreClientInformation.class);
     
     /** The client information manager used for storing the information. */
-    @Nullable private ClientInformationManager clientInformationManager;
+    @NonnullAfterInit private ClientInformationManager clientInformationManager;
     
     /** Strategy to obtain registration validity period policy. */
     @Nullable private Function<ProfileRequestContext,Duration> registrationValidityPeriodStrategy;
     
-    /** Strategy used to locate the {@link OIDCClientRegistrationTokenClaimsContext} associated with the request. */
-    @Nonnull private Function<ProfileRequestContext,OIDCClientRegistrationTokenClaimsContext>
-        registrationTokenContextLookupStrategy;
-    
-    /** The OIDCClientRegistrationTokenClaimsContext from which to optionally obtain client ID. */
-    @Nullable private OIDCClientRegistrationTokenClaimsContext registrationTokenCtx;
-    
-    /** The response message. */
-    @Nullable private OIDCClientInformationResponse response;
-    
+    /** Strategy used to locate {@link OIDCClientInformation} to be stored. */
+    @Nonnull private Function<ProfileRequestContext,OIDCClientInformation> clientInformationLookupStrategy;
+
+    /** Condition used to determine if existing record should be replaced. */
+    @Nonnull private Predicate<ProfileRequestContext> replacementCondition;
+
     /** Constructor. */
     public StoreClientInformation() {
-        registrationTokenContextLookupStrategy = new DefaultOIDCClientRegistrationTokenClaimsContextLookupFunction();
+        clientInformationLookupStrategy = new DefaultClientInformationLookupFunction();
+        replacementCondition = new DefaultClientInformationReplacementCondition();
     }
     
     /**
@@ -79,8 +75,7 @@ public class StoreClientInformation extends AbstractProfileAction {
      */
     public void setRegistrationValidityPeriodStrategy(
             @Nullable final Function<ProfileRequestContext,Duration> strategy) {
-        ifInitializedThrowUnmodifiabledComponentException();
-        
+        checkSetterPreconditions();
         registrationValidityPeriodStrategy = strategy;
     }
     
@@ -89,31 +84,43 @@ public class StoreClientInformation extends AbstractProfileAction {
      * 
      * @return The client information manager used for storing the information
      */
-    @NonnullAfterInit public ClientInformationManager getClientInformationManager() {
+    @Nonnull public ClientInformationManager getClientInformationManager() {
+        checkComponentActive();
         return clientInformationManager;
     }
     
     /**
      * Set the client information manager used for storing the information.
+     * 
      * @param manager The client information manager used for storing the information.
      */
     public void setClientInformationManager(@Nonnull final ClientInformationManager manager) {
-        ifInitializedThrowUnmodifiabledComponentException();
+        checkSetterPreconditions();
         clientInformationManager = Constraint.isNotNull(manager, "The client information manager cannot be null!");
     }
-    
+
     /**
-     * Set the strategy used to locate the {@link OIDCClientRegistrationTokenClaimsContext} associated with a given
-     * request.
+     * Set the strategy used to locate {@link OIDCClientInformation} to be stored.
      * 
      * @param strategy lookup strategy
+     * 
+     * @since 4.4.0
      */
-    public void setRegistrationTokenContextLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext,OIDCClientRegistrationTokenClaimsContext> strategy) {
-        ifInitializedThrowUnmodifiabledComponentException();
-        
-        registrationTokenContextLookupStrategy = Constraint.isNotNull(strategy,
-                "OIDCClientRegistrationTokenClaimsContext lookup strategy cannot be null");
+    public void setClientInformationLookupStrategy(@Nonnull final Function<ProfileRequestContext,OIDCClientInformation> strategy) {
+        checkSetterPreconditions();
+        clientInformationLookupStrategy = Constraint.isNotNull(strategy, "Client information lookup strategy cannot be null");
+    }
+
+    /**
+     * Set the condition used to determine if existing record should be replaced.
+     * 
+     * @param condition replacement condition
+     * 
+     * @since 4.4.0
+     */
+    public void setReplacementCondition(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        checkSetterPreconditions();
+        replacementCondition = Constraint.isNotNull(condition, "Replacement condition cannot be null");
     }
 
     /** {@inheritDoc} */
@@ -126,41 +133,11 @@ public class StoreClientInformation extends AbstractProfileAction {
         }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        if (!super.doPreExecute(profileRequestContext)) {
-            return false;
-        }
-        
-        if (profileRequestContext.getOutboundMessageContext() == null) {
-            log.error("{} Unable to locate outbound message context", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
-            return false;
-        }
-        
-        final Object message = profileRequestContext.ensureOutboundMessageContext().getMessage();
-        if (message == null || !(message instanceof OIDCClientInformationResponse)) {
-            log.error("{} Unable to locate outbound message", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
-            return false;
-        }
-        
-        registrationTokenCtx = registrationTokenContextLookupStrategy.apply(profileRequestContext);
-        if (registrationTokenCtx != null && registrationTokenCtx.getClaimsSet() == null) {
-            registrationTokenCtx = null;
-        }
-        
-        response = (OIDCClientInformationResponse) message;
-        return true;
-    }
-    
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        assert response != null;
-        final OIDCClientInformation clientInformation = response.getOIDCClientInformation();
+        final OIDCClientInformation clientInformation = clientInformationLookupStrategy.apply(profileRequestContext);
         if (clientInformation == null) {
             log.error("{} Unable to locate client information from the response message", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
@@ -169,15 +146,7 @@ public class StoreClientInformation extends AbstractProfileAction {
         Duration lifetime = registrationValidityPeriodStrategy != null ?
                 registrationValidityPeriodStrategy.apply(profileRequestContext) : null;
 
-        final boolean replace;
-        if (registrationTokenCtx != null) {
-            final RegistrationClaimsSet claimsSet = registrationTokenCtx.getClaimsSet();
-            assert claimsSet != null;
-            replace = claimsSet.isReplacement();
-            
-        } else {
-            replace = false;
-        }
+        final boolean replace = replacementCondition.test(profileRequestContext);
         
         log.debug("{} Storing client information (replace = {})", getLogPrefix(), replace);
         
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultClientInformationReplacementCondition.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultClientInformationReplacementCondition.java
new file mode 100644
index 00000000..3be5f9c1
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultClientInformationReplacementCondition.java
@@ -0,0 +1,60 @@
+/*
+ * 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.profile.logic;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationTokenClaimsContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCClientRegistrationTokenClaimsContextLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.token.support.RegistrationClaimsSet;
+
+/**
+ * Default condition that bases on {@link RegistrationClaimsSet#isReplacement()} if it's set in
+ * {@link OIDCClientRegistrationTokenClaimsContext}. Otherwise, false is returned.
+ * 
+ * @since 4.4.0
+ */
+public class DefaultClientInformationReplacementCondition implements Predicate<ProfileRequestContext> {
+
+    /** Strategy used to locate the {@link OIDCClientRegistrationTokenClaimsContext} associated with the request. */
+    @Nonnull private Function<ProfileRequestContext,OIDCClientRegistrationTokenClaimsContext>
+        registrationTokenContextLookupStrategy;
+
+    /**
+     * Constructor.
+     */
+    public DefaultClientInformationReplacementCondition() {
+        registrationTokenContextLookupStrategy = new DefaultOIDCClientRegistrationTokenClaimsContextLookupFunction();
+
+    }
+    /** {@inheritDoc} */
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext profileRequestContext) {
+        final OIDCClientRegistrationTokenClaimsContext registrationTokenCtx =
+                registrationTokenContextLookupStrategy.apply(profileRequestContext);
+        if (registrationTokenCtx != null && registrationTokenCtx.getClaimsSet() != null) {
+            final RegistrationClaimsSet claimsSet = registrationTokenCtx.getClaimsSet();
+            assert claimsSet != null;
+            return claimsSet.isReplacement();
+        }
+        return false;
+    }
+}
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-info/oidc-abstract-api-info-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-info/oidc-abstract-api-info-flow.xml
index 1f6bd85c..aae199c0 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-info/oidc-abstract-api-info-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-info/oidc-abstract-api-info-flow.xml
@@ -17,13 +17,16 @@
     </action-state>
 
     <decision-state id="CheckInboundInterceptContext">
+        <on-entry>
+            <evaluate expression="flowRequestContext.getFlowScope().get('transitionAfterInboundIntercept') != null ? flowRequestContext.getFlowScope().get('transitionAfterInboundIntercept') : 'BuildResponseMessage'" result="flowScope.postInboundInterceptTransition"/>
+        </on-entry>
         <if test="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.ProfileInterceptorContext)).getAvailableFlows().isEmpty()"
-            then="BuildResponseMessage" else="DoInboundInterceptSubflow" />
+            then="#{postInboundInterceptTransition}" else="DoInboundInterceptSubflow" />
     </decision-state>
 
     <subflow-state id="DoInboundInterceptSubflow" subflow="intercept">
         <input name="calledAsSubflow" value="true" />
-        <transition on="proceed" to="BuildResponseMessage" />
+        <transition on="proceed" to="#{postInboundInterceptTransition}" />
     </subflow-state>
 
     <bean-import resource="classpath:/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-info/oidc-abstract-api-info-beans.xml" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-beans.xml
new file mode 100644
index 00000000..1d01bc04
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-beans.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c"
+    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <bean id="shibboleth.oidc.browserProfile" class="java.lang.Boolean" c:_0="false" />
+
+    <bean id="InitializeOutboundMessageContext"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeOutboundRegistrationResponseMessageContext"
+        scope="prototype">
+    </bean>
+
+    <bean id="InitializeRelyingPartyContext"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext"
+        scope="prototype" />
+
+    <bean id="AddRedirectUrisToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRedirectUrisToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddTokenEndpointAuthMethodsToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTokenEndpointAuthMethodsToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"
+        p:tokenEndpointAuthMethodsLookupStrategy-ref="shibboleth.oidc.TokenEndpointAuthMethodsLookupStrategy"/>
+
+    <bean id="AddApplicationTypeToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddApplicationTypeToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddScopeToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddScopeToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"
+        p:defaultScope-ref="shibboleth.oidc.DefaultScope" />
+
+    <bean id="AddContactsToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddContactsToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddGrantTypeToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddGrantTypeToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddSubjectTypeToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddSubjectTypeToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"
+        p:defaultSubjectType-ref="shibboleth.oidc.DefaultSubjectType" />
+
+    <bean id="AddLogoUrisToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddLogoUrisToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddPolicyUrisToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddPolicyUrisToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddTosUrisToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTosUrisToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddClientNameToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddClientNameToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddSecurityConfigurationToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddSecurityConfigurationToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddRequestObjectSecurityConfigurationToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRequestObjectSecurityConfigurationToClientMetadata"
+        p:allowSignatureNone="%{idp.oidc.dynreg.allowNoneForRequestSigning:true}"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddRequestUrisToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRequestUrisToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddLogoutParametersToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddLogoutParametersToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddRemainingClaimsToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRemainingClaimsToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="AddResponseTypesToClientMetadata"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddResponseTypesToClientMetadata"
+        scope="prototype"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"/>
+
+    <bean id="BuildClientInformation"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.BuildClientInformation"
+        scope="prototype" />
+
+    <bean id="oidc.messageEncoderFactory"
+        class="net.shibboleth.idp.plugin.oidc.op.encoding.impl.OIDCResponseEncoderFactory"
+        p:messageEncoder-ref="oidc.nimbusEncoder" scope="prototype" />
+
+    <bean id="oidc.nimbusEncoder"
+        class="net.shibboleth.idp.plugin.oidc.op.encoding.impl.NimbusResponseEncoder"
+        scope="prototype"
+        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}"
+        init-method="" />
+
+    <bean id="EncodeMessage"
+        class="org.opensaml.profile.action.impl.EncodeMessage"
+        scope="prototype"
+        p:messageEncoderFactory-ref="oidc.messageEncoderFactory"
+        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
+
+</beans>
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-flow.xml
similarity index 67%
copy from idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml
copy to idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-flow.xml
index 637c5620..055116b8 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-flow.xml
@@ -3,26 +3,12 @@
     xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
     parent="oidc/abstract-api">
 
+    <!-- If the extending flows may start with this action-state, they need to add the transition logic. -->
     <action-state id="InitializeMandatoryContexts">
         <evaluate expression="InitializeProfileRequestContext" />
         <evaluate expression="PopulateMetricContext" />
         <evaluate expression="FlowStartPopulateAuditContext" />
         <evaluate expression="InitializeOutboundMessageContext" />
-        <evaluate expression="'proceed'" />
-        <transition on="proceed" to="DecodeMessage">
-            <set name="flowScope.transitionAfterDecode" value="'PostDecodeMessage'" />
-         </transition>
-    </action-state>
-
-    <action-state id="PostDecodeMessage">
-        <evaluate expression="InitializeRelyingPartyContext" />
-        <evaluate expression="ValidateRegistrationAccessToken" />
-        <evaluate expression="SelectRelyingPartyConfiguration" />
-        <evaluate expression="SelectProfileConfiguration" />
-        <evaluate expression="PopulateInboundInterceptContext" />
-        <evaluate expression="'proceed'" />
-        <transition on="proceed"
-            to="CheckInboundInterceptContext" />
     </action-state>
 
     <decision-state id="CheckInboundInterceptContext">
@@ -35,15 +21,10 @@
         <transition on="proceed" to="OutboundContextsAndSecurityParameters" />
     </subflow-state>
 
-    <action-state id="OutboundContextsAndSecurityParameters">
-        <evaluate expression="InitializeRegistrationMetadataPolicyContext" />
-        <evaluate expression="ValidateRegistrationRequestMetadata" />
-        <evaluate expression="CheckRedirectURIs" />
-        <evaluate expression="'proceed'" />
-        <transition on="proceed" to="BuildResponse" />
-    </action-state>
-    
     <action-state id="BuildResponse">
+        <on-entry>
+            <evaluate expression="flowRequestContext.getFlowScope().get('transitionAfterBuildResponse') != null ? flowRequestContext.getFlowScope().get('transitionAfterBuildResponse') : 'BuildResponseMessage'" result="flowScope.postBuildResponseTransition"/>
+        </on-entry>
         <evaluate expression="GenerateClientID" />
         <evaluate expression="GenerateClientSecret" />
         <evaluate expression="AddRedirectUrisToClientMetadata" />
@@ -64,20 +45,22 @@
         <evaluate expression="AddRequestUrisToClientMetadata" />
         <evaluate expression="AddLogoutParametersToClientMetadata" />
         <evaluate expression="AddRemainingClaimsToClientMetadata" />
+        <evaluate expression="BuildClientInformation" />
         <evaluate expression="'proceed'" />
-        <transition on="proceed" to="BuildResponseMessage" />
-    </action-state>
-
-    <action-state id="BuildResponseMessage">
-        <transition on="proceed" to="StoreClientInformation" />
+        <transition on="proceed" to="#{postBuildResponseTransition}">
+            <set name="flowScope.transitionAfterOutboundIntercept" value="'StoreClientInformation'" />
+        </transition>
     </action-state>
 
     <action-state id="StoreClientInformation">
+        <on-entry>
+            <set name="flowScope.transitionAfterOutboundIntercept" value="#null" />
+        </on-entry>
         <evaluate expression="StoreClientInformation" />
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="CommitResponse" />
     </action-state>
 
-    <bean-import resource="register-beans.xml" />
+    <bean-import resource="classpath:/META-INF/net/shibboleth/idp/flows/oidc/abstract-register/oidc-abstract-register-beans.xml" />
 
 </flow>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-flow.xml
index c453f19a..33d4aef5 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-flow.xml
@@ -28,15 +28,16 @@
 
     <decision-state id="CheckOutboundInterceptContext">
         <on-entry>
+            <evaluate expression="flowRequestContext.getFlowScope().get('transitionAfterOutboundIntercept') != null ? flowRequestContext.getFlowScope().get('transitionAfterOutboundIntercept') : 'CommitResponse'" result="flowScope.postOutboundInterceptTransition"/>
             <evaluate expression="PopulateOutboundInterceptContext" />
         </on-entry>
         <if test="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.ProfileInterceptorContext)).getAvailableFlows().isEmpty()"
-            then="CommitResponse" else="DoOutboundInterceptSubflow" />
+            then="#{postOutboundInterceptTransition}" else="DoOutboundInterceptSubflow" />
     </decision-state>
 
     <subflow-state id="DoOutboundInterceptSubflow" subflow="intercept">
         <input name="calledAsSubflow" value="true" />
-        <transition on="proceed" to="CommitResponse" />
+        <transition on="proceed" to="#{postOutboundInterceptTransition}" />
         <transition to="HandleError" />
     </subflow-state>
 
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-beans.xml
index 0795687d..11b19881 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-beans.xml
@@ -19,11 +19,6 @@
     <util:constant id="shibboleth.metrics.ProfileCounter"
         static-field="net.shibboleth.oidc.profile.config.impl.DefaultOIDCDynamicRegistrationConfiguration.PROFILE_COUNTER" />
 
-    <bean id="InitializeOutboundMessageContext"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeOutboundRegistrationResponseMessageContext"
-        scope="prototype">
-    </bean>
-
     <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
         <constructor-arg>
             <bean
@@ -36,10 +31,6 @@
         </constructor-arg>
     </bean>
 
-    <bean id="InitializeRelyingPartyContext"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext"
-        scope="prototype" />
-
     <bean id="ValidateRegistrationAccessToken"
         class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRegistrationAccessToken" scope="prototype"
         p:revocationCache-ref="shibboleth.oidc.RevocationCache"
@@ -85,22 +76,11 @@
         </property>
     </bean>
 
-    <bean id="AddRedirectUrisToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRedirectUrisToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddTokenEndpointAuthMethodsToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTokenEndpointAuthMethodsToClientMetadata"
-        scope="prototype" />
+    <bean id="shibboleth.oidc.InputMetadataLookupStrategy"
+        class="net.shibboleth.idp.plugin.oidc.op.messaging.context.navigate.OIDCPolicyEnforcedClientRegistrationRequestMetadataLookupFunction" />
 
-    <bean id="AddApplicationTypeToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddApplicationTypeToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddScopeToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddScopeToClientMetadata"
-        scope="prototype"
-        p:defaultScope-ref="shibboleth.oidc.DefaultScope" />
+    <bean id="shibboleth.oidc.TokenEndpointAuthMethodsLookupStrategy"
+        class="net.shibboleth.oidc.profile.config.navigate.TokenEndpointAuthMethodLookupFunction" />
 
     <bean id="shibboleth.oidc.DefaultScope"
         class="com.nimbusds.oauth2.sdk.Scope" factory-method="parse">
@@ -108,19 +88,6 @@
             value="#{'%{idp.oidc.dynreg.defaultScope:openid profile email address phone offline_access}'.trim()}" />
     </bean>
 
-    <bean id="AddContactsToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddContactsToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddGrantTypeToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddGrantTypeToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddSubjectTypeToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddSubjectTypeToClientMetadata"
-        scope="prototype"
-        p:defaultSubjectType-ref="shibboleth.oidc.DefaultSubjectType" />
-
     <bean id="shibboleth.oidc.DefaultSubjectType"
         class="com.nimbusds.openid.connect.sdk.SubjectType"
         factory-method="parse">
@@ -128,56 +95,23 @@
             value="#{'%{idp.oidc.dynreg.defaultSubjectType:public}'.trim()}" />
     </bean>
 
-    <bean id="AddResponseTypesToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddResponseTypesToClientMetadata"
-        scope="prototype" />
-
     <bean id="AddJwksToClientMetadata"
         class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddJwksToClientMetadata"
         scope="prototype"
         p:httpClient="#{getObject('shibboleth.oidc.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
         p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.NonBrowser.HttpClientSecurityParameters')}"
+        p:oidcInputMetadataLookupStrategy-ref="shibboleth.oidc.InputMetadataLookupStrategy"
         p:validateRemoteJwkSetPredicate-ref="%{idp.oidc.dynreg.validateRemoteJwks:shibboleth.Conditions.TRUE}"/>
 
-    <bean id="AddLogoUrisToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddLogoUrisToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddPolicyUrisToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddPolicyUrisToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddTosUrisToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTosUrisToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddClientNameToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddClientNameToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddSecurityConfigurationToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddSecurityConfigurationToClientMetadata"
-        scope="prototype" />
-
-    <bean id="AddRequestObjectSecurityConfigurationToClientMetadata"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRequestObjectSecurityConfigurationToClientMetadata"
-        p:allowSignatureNone="%{idp.oidc.dynreg.allowNoneForRequestSigning:true}" scope="prototype" />
-
-    <bean id="AddRequestUrisToClientMetadata" scope="prototype"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRequestUrisToClientMetadata" />
-
-    <bean id="AddLogoutParametersToClientMetadata" scope="prototype"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddLogoutParametersToClientMetadata" />
-
-    <bean id="AddRemainingClaimsToClientMetadata" scope="prototype"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddRemainingClaimsToClientMetadata" />
-
     <bean id="StoreClientInformation"
             class="net.shibboleth.idp.plugin.oidc.op.profile.impl.StoreClientInformation" scope="prototype"
             p:clientInformationManager-ref="#{'%{idp.oidc.dynreg.clientInformationManager:shibboleth.oidc.ClientInformationManager}'.trim()}">
         <property name="registrationValidityPeriodStrategy">
             <bean class="net.shibboleth.oidc.profile.config.navigate.RegistrationValidityPeriodLookupFunction" />
         </property>
+        <property name="replacementCondition">
+            <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultClientInformationReplacementCondition" />
+        </property>
     </bean>
 
     <bean id="BuildErrorResponseFromEvent"
@@ -192,26 +126,9 @@
     </bean>
 
     <bean id="FormOutboundMessage"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.BuildClientInformation"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.FormOutboundClientInformationResponseMessage"
         scope="prototype" />
 
-    <bean id="oidc.messageEncoderFactory"
-        class="net.shibboleth.idp.plugin.oidc.op.encoding.impl.OIDCResponseEncoderFactory"
-        p:messageEncoder-ref="oidc.nimbusEncoder" scope="prototype" />
-
-    <bean id="oidc.nimbusEncoder"
-        class="net.shibboleth.idp.plugin.oidc.op.encoding.impl.NimbusResponseEncoder"
-        scope="prototype"
-        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
-        p:objectMapper-ref="#{'%{idp.oidc.logging.objectMapper:shibboleth.oidc.JSONObjectMapper}'.trim()}"
-        init-method="" />
-
-    <bean id="EncodeMessage"
-        class="org.opensaml.profile.action.impl.EncodeMessage"
-        scope="prototype"
-        p:messageEncoderFactory-ref="oidc.messageEncoderFactory"
-        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
-
     <bean id="PostResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
         p:fieldExtractors="#{getObject('shibboleth.oidc.RegistrationPostResponseAuditExtractors') ?: getObject('shibboleth.oidc.DefaultRegistrationPostResponseAuditExtractors')}" />
 
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml
index 637c5620..7da54f34 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/register/register-flow.xml
@@ -1,13 +1,9 @@
 <flow xmlns="http://www.springframework.org/schema/webflow"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
-    parent="oidc/abstract-api">
+    parent="oidc/abstract-register">
 
     <action-state id="InitializeMandatoryContexts">
-        <evaluate expression="InitializeProfileRequestContext" />
-        <evaluate expression="PopulateMetricContext" />
-        <evaluate expression="FlowStartPopulateAuditContext" />
-        <evaluate expression="InitializeOutboundMessageContext" />
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="DecodeMessage">
             <set name="flowScope.transitionAfterDecode" value="'PostDecodeMessage'" />
@@ -21,20 +17,9 @@
         <evaluate expression="SelectProfileConfiguration" />
         <evaluate expression="PopulateInboundInterceptContext" />
         <evaluate expression="'proceed'" />
-        <transition on="proceed"
-            to="CheckInboundInterceptContext" />
+        <transition on="proceed" to="CheckInboundInterceptContext" />
     </action-state>
 
-    <decision-state id="CheckInboundInterceptContext">
-        <if test="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.ProfileInterceptorContext)).getAvailableFlows().isEmpty()"
-            then="OutboundContextsAndSecurityParameters" else="DoInboundInterceptSubflow" />
-    </decision-state>
-
-    <subflow-state id="DoInboundInterceptSubflow" subflow="intercept">
-        <input name="calledAsSubflow" value="true" />
-        <transition on="proceed" to="OutboundContextsAndSecurityParameters" />
-    </subflow-state>
-
     <action-state id="OutboundContextsAndSecurityParameters">
         <evaluate expression="InitializeRegistrationMetadataPolicyContext" />
         <evaluate expression="ValidateRegistrationRequestMetadata" />
@@ -43,41 +28,6 @@
         <transition on="proceed" to="BuildResponse" />
     </action-state>
     
-    <action-state id="BuildResponse">
-        <evaluate expression="GenerateClientID" />
-        <evaluate expression="GenerateClientSecret" />
-        <evaluate expression="AddRedirectUrisToClientMetadata" />
-        <evaluate expression="AddApplicationTypeToClientMetadata" />
-        <evaluate expression="AddScopeToClientMetadata" />
-        <evaluate expression="AddGrantTypeToClientMetadata" />
-        <evaluate expression="AddResponseTypesToClientMetadata" />
-        <evaluate expression="AddSubjectTypeToClientMetadata" />
-        <evaluate expression="AddContactsToClientMetadata" />
-        <evaluate expression="AddJwksToClientMetadata" />
-        <evaluate expression="AddTokenEndpointAuthMethodsToClientMetadata" />
-        <evaluate expression="AddLogoUrisToClientMetadata" />
-        <evaluate expression="AddPolicyUrisToClientMetadata" />
-        <evaluate expression="AddTosUrisToClientMetadata" />
-        <evaluate expression="AddClientNameToClientMetadata" />
-        <evaluate expression="AddSecurityConfigurationToClientMetadata" />
-        <evaluate expression="AddRequestObjectSecurityConfigurationToClientMetadata" />
-        <evaluate expression="AddRequestUrisToClientMetadata" />
-        <evaluate expression="AddLogoutParametersToClientMetadata" />
-        <evaluate expression="AddRemainingClaimsToClientMetadata" />
-        <evaluate expression="'proceed'" />
-        <transition on="proceed" to="BuildResponseMessage" />
-    </action-state>
-
-    <action-state id="BuildResponseMessage">
-        <transition on="proceed" to="StoreClientInformation" />
-    </action-state>
-
-    <action-state id="StoreClientInformation">
-        <evaluate expression="StoreClientInformation" />
-        <evaluate expression="'proceed'" />
-        <transition on="proceed" to="CommitResponse" />
-    </action-state>
-
     <bean-import resource="register-beans.xml" />
 
 </flow>
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformationTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformationTest.java
index 21603ff3..efa610f6 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformationTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/BuildClientInformationTest.java
@@ -28,7 +28,6 @@ import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
 import com.nimbusds.oauth2.sdk.auth.Secret;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformationResponse;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 
 import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCClientRegistrationResponseContext;
@@ -71,13 +70,6 @@ public class BuildClientInformationTest {
         registrationCtx.setClientMetadata(metadata);
     }
 
-    @Test
-    public void noOutboundMessageContext() {
-        final ProfileRequestContext localPrc = new ProfileRequestContext();
-        action.execute(localPrc);
-        ActionTestingSupport.assertEvent(localPrc, EventIds.INVALID_PROFILE_CTX);
-    }
-    
     @Test
     public void noMetadataContext() {
         final ProfileRequestContext localPrc = new ProfileRequestContext();
@@ -168,19 +160,16 @@ public class BuildClientInformationTest {
     protected void assertSuccessfulResponse(boolean secret) {
         assert profileRequestCtx != null;
         ActionTestingSupport.assertProceedEvent(profileRequestCtx);
-        final OIDCClientInformationResponse response = (OIDCClientInformationResponse) messageCtx.getMessage();
-        Assert.assertNotNull(response);
-        assert response != null;
-        final OIDCClientInformation clientInformation = response.getOIDCClientInformation();
+        final OIDCClientInformation clientInformation = registrationCtx.getClientInformation();
         assert clientInformation != null;
         Assert.assertEquals(clientInformation.getID(), new ClientID(clientId));
         if (secret) {
-            assertSecret(response);        
+            assertSecret(clientInformation);
         }
     }
 
-    protected void assertSecret(final OIDCClientInformationResponse response) {
-        final Secret secret = response.getOIDCClientInformation().getSecret();
+    protected void assertSecret(final OIDCClientInformation information) {
+        final Secret secret = information.getSecret();
         Assert.assertNotNull(secret);
         Assert.assertEquals(secret.getValue(), clientSecret);
         Assert.assertNull(secret.getExpirationDate());
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectUrisTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectUrisTest.java
index 0a292b87..b2f47061 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectUrisTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/CheckRedirectUrisTest.java
@@ -67,7 +67,7 @@ public class CheckRedirectUrisTest extends BaseOIDCRegistrationRequestTest {
     @Test
     public void testNoMessage() throws ComponentInitializationException {
         setUpContext(null);
-        ActionTestingSupport.assertEvent(action.execute(requestCtx), EventIds.INVALID_MSG_CTX);
+        ActionTestingSupport.assertEvent(action.execute(requestCtx), EventIds.INVALID_MESSAGE);
     }
     
     @Test

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


More information about the commits mailing list