[java-idp-plugin-oidc-rp] branch main updated: First attempt to integrate the new JWT Trust engine for sig validation

Phil Smart philip.smart at jisc.ac.uk
Fri Apr 29 16:12:32 UTC 2022


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

philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.

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

The following commit(s) were added to refs/heads/main by this push:
     new 5b2c770  First attempt to integrate the new JWT Trust engine for sig validation
5b2c770 is described below

commit 5b2c7709d7a17258655523115e093d7f859243f0
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Apr 29 17:12:26 2022 +0100

    First attempt to integrate the new JWT Trust engine for sig validation
    
    Most the heavy lifting is in oidc-common
    Will break tests until synchronised with oidc-common
---
 idp-oidc-rp-api/pom.xml                            |   3 +-
 ...atureValidationConfigurationLookupFunction.java |  92 +++
 .../oidc/rp/context/AbstractOIDCEntityContext.java |  38 ++
 .../oidc/rp/context/OIDCPeerEntityContext.java     |  29 +-
 .../oidc/rp/impl/AuthorizationController.java      |   2 +-
 ...nitializeOAuth2ClientAuthenticationContext.java |   6 +-
 .../authn/oidc/rp/impl/MockCredentialResolver.java |  35 ++
 .../rp/impl/PrepareOIDCInboundMessageContext.java  |  57 +-
 .../oidc/rp/impl/ValidateIDTokenSignature.java     | 108 ----
 .../impl/OIDCProviderMetadataLookupHandler.java    | 132 ++++-
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  33 ++
 .../oidc-relying-party-authn-beans.xml             | 657 +++++++++++----------
 .../oidc-relying-party-authn-flow.xml              |   9 +-
 .../idp/service/relying-party/postconfig.xml       |  42 +-
 .../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java  |  51 +-
 .../resources/conf/test-relying-party-system.xml   |   8 +-
 pom.xml                                            |   6 +-
 17 files changed, 808 insertions(+), 500 deletions(-)

diff --git a/idp-oidc-rp-api/pom.xml b/idp-oidc-rp-api/pom.xml
index ace1fa8..dd176a6 100644
--- a/idp-oidc-rp-api/pom.xml
+++ b/idp-oidc-rp-api/pom.xml
@@ -20,12 +20,13 @@
 	</properties>
 
 	<dependencies>
+        
 		<!-- Provided dependencies -->
 		<dependency>
 			<groupId>com.google.code.findbugs</groupId>
 			<artifactId>jsr305</artifactId>
 			<scope>provided</scope>
-		</dependency>
+		</dependency>        
 		 <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
new file mode 100644
index 0000000..c4856ff
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenSignatureValidationConfigurationLookupFunction.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.authn.oidc.rp.config.navigate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.profile.config.ProfileConfiguration;
+import net.shibboleth.idp.profile.config.SecurityConfiguration;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
+import net.shibboleth.idp.relyingparty.RelyingPartyConfigurationResolver;
+import net.shibboleth.oidc.profile.config.OIDCSecurityConfiguration;
+import net.shibboleth.oidc.security.SignatureValidationConfiguration;
+
+/**
+ * A function that returns a {@link SignatureValidationConfiguration} list for id_token signature validation by way
+ * of various lookup strategies. 
+ * 
+ * <p>
+ * If a specific setting is unavailable, a null value is returned.
+ * </p>
+ */
+public class IDTokenSignatureValidationConfigurationLookupFunction 
+            extends AbstractRelyingPartyLookupFunction<List<SignatureValidationConfiguration>> {
+
+    /** A resolver for default security configurations. */
+    @Nullable
+    private RelyingPartyConfigurationResolver rpResolver;
+
+    /**
+     * Set the resolver for default security configurations.
+     * 
+     * @param resolver the resolver to use
+     */
+    public void setRelyingPartyConfigurationResolver(@Nullable final RelyingPartyConfigurationResolver resolver) {
+        rpResolver = resolver;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable
+    public List<SignatureValidationConfiguration> apply(@Nullable final ProfileRequestContext input) {
+
+        final List<SignatureValidationConfiguration> configs = new ArrayList<>();
+
+        final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
+        if (rpc != null) {
+            final ProfileConfiguration pc = rpc.getProfileConfig();
+            if (pc != null && pc.getSecurityConfiguration(input) instanceof OIDCSecurityConfiguration
+                    && ((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
+                            .getIdTokenJwtSignatureValidationConfig() != null) {
+                configs.add(((OIDCSecurityConfiguration) pc.getSecurityConfiguration(input))
+                        .getIdTokenJwtSignatureValidationConfig());
+            }
+        }
+
+        // Check for a per-profile default (relying party independent) config.
+        if (input != null && rpResolver != null) {
+            final SecurityConfiguration defaultConfig =
+                    rpResolver.getDefaultSecurityConfiguration(input.getProfileId());
+            if (defaultConfig instanceof OIDCSecurityConfiguration
+                    && ((OIDCSecurityConfiguration) defaultConfig)
+                    .getIdTokenJwtSignatureValidationConfig() != null) {
+                configs.add(
+                        ((OIDCSecurityConfiguration) defaultConfig).getIdTokenJwtSignatureValidationConfig());
+            }
+        }
+        // TODO: Support for Global Default configuration?
+        return configs;
+    }
+}
+
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java
new file mode 100644
index 0000000..418d661
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/AbstractOIDCEntityContext.java
@@ -0,0 +1,38 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.context;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+
+/**
+ * Abstract base class for subcontexts that carry information about a OIDC entity.  This context will often
+ * contain subcontexts, whose data is construed to be scoped to that entity.
+ */
+public class AbstractOIDCEntityContext extends BaseContext {
+    
+    /** The identifier of the OIDC peer entity e.g. issuerId or ClientId. */
+    @Nullable @NotEmpty private String identifer;
+    
+    /**
+     * Gets the identifier of the OIDC entity.
+     * 
+     * @return identifier of the OIDC entity, may be null
+     */
+    @Nullable @NotEmpty public String getIdentifier() {
+        return identifer;
+    }
+
+    /**
+     * Sets the identifier of the OIDC entity e.g. issuerId or ClientId.
+     * 
+     * @param id the new identifier
+     */
+    public void setIdentifier(@Nullable final String id) {
+        identifer = StringSupport.trimOrNull(id);
+    }
+
+}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/OIDCPeerEntityContext.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/OIDCPeerEntityContext.java
index 86dcc70..97bb68b 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/OIDCPeerEntityContext.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/context/OIDCPeerEntityContext.java
@@ -17,13 +17,6 @@
 
 package net.shibboleth.idp.plugin.authn.oidc.rp.context;
 
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.BaseContext;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
-
 /**
  * Lightweight subcontext that carries information about a OIDC peer entity.
  * 
@@ -31,27 +24,9 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
  * This context will often contain subcontexts, whose data is construed to be scoped to that peer entity.
  * </p>
  */
-public final class OIDCPeerEntityContext extends BaseContext {
+//TODO this is just a marker interface?
+public final class OIDCPeerEntityContext extends AbstractOIDCEntityContext {
     
-    /** The identifier of the OIDC peer entity e.g. issuerId or ClientId. */
-    @Nullable @NotEmpty private String identifer;
     
-    /**
-     * Gets the identifier of the OIDC entity.
-     * 
-     * @return identifier of the OIDC entity, may be null
-     */
-    @Nullable @NotEmpty public String getIdentifier() {
-        return identifer;
-    }
-
-    /**
-     * Sets the identifier of the OIDC entity e.g. issuerId or ClientId.
-     * 
-     * @param id the new identifier
-     */
-    public void setIdentifier(@Nullable final String id) {
-        identifer = StringSupport.trimOrNull(id);
-    }
 
 }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
index 15a609c..456afc8 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthorizationController.java
@@ -332,7 +332,7 @@ public class AuthorizationController extends AbstractInitializableComponent {
             return;
         }
         log.debug("OIDC response_type '{}' and response_mode '{}' requested, decoding incoming request", 
-                responseCtx.getResponseMode(), responseCtx.getResponseType());
+                responseCtx.getResponseType(), responseCtx.getResponseMode());
         
         try {
             final MessageDecoder decoder = 
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationContext.java
index a2e4867..e9d564a 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationContext.java
@@ -53,10 +53,10 @@ public class InitializeOAuth2ClientAuthenticationContext extends AbstractProfile
     @Nonnull
     private final Logger log = LoggerFactory.getLogger(InitializeOAuth2ClientAuthenticationContext.class);
     
-
     /** 
      * The strategy used to lookup or create the {@link OAuth2ClientAuthenticationContext} 
-     * for storing the client authentication.*/
+     * for storing the client authentication.
+     */
     @Nonnull private Function<ProfileRequestContext, OAuth2ClientAuthenticationContext> 
                                                     oauth2ClientAuthenticationContextLookupStrategy;
         
@@ -136,7 +136,7 @@ public class InitializeOAuth2ClientAuthenticationContext extends AbstractProfile
             profileConfiguration = (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
         }
         if (profileConfiguration == null) {
-            log.error("{} OIDCAuthorizationConfiguration not found", getLogPrefix());
+            log.error("{} Profile configuration not found", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
             return false;
         }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockCredentialResolver.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockCredentialResolver.java
new file mode 100644
index 0000000..7d9f43c
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockCredentialResolver.java
@@ -0,0 +1,35 @@
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.List;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialResolver;
+
+import com.nimbusds.jose.Algorithm;
+
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+// TODO tmp class to fit into the trust engine.
+public class MockCredentialResolver implements CredentialResolver {
+    
+    private static final String ID_TOKEN_HMAC_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
+
+    @Override
+    public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+        return List.of(resolveSingle(criteria));
+    }
+
+    @Override
+    public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+        final var cred = new BasicJWKCredential();
+        cred.setAlgorithm(Algorithm.parse("HS256"));
+        cred.setSecretKey(new SecretKeySpec(ID_TOKEN_HMAC_SECRET.getBytes(), "HS256"));
+        return cred;
+        
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PrepareOIDCInboundMessageContext.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PrepareOIDCInboundMessageContext.java
index 9c45c99..509273a 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PrepareOIDCInboundMessageContext.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/PrepareOIDCInboundMessageContext.java
@@ -18,6 +18,7 @@
 package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
 
 import java.util.function.Function;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -29,6 +30,8 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Predicates;
+
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
@@ -42,6 +45,9 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
  * {@link ProfileRequestContext} based on the identity of a relying party, by default from the 
  * {@link AuthenticationContext#getAuthenticatingAuthority()}.
  * 
+ * <p>If {@link #addToExistingInboundMessageContext} is true, the {@link OIDCPeerEntityContext} is
+ * added as a subcontext to any existing inbound message context.</p>  
+ * 
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_PROFILE_CTX}
  */
@@ -56,6 +62,18 @@ public class PrepareOIDCInboundMessageContext extends AbstractProfileAction {
     /** The identifier of the OP/RP to base the inbound context on. */
     @Nullable private String identifier;
     
+    /** 
+     * Should the peer entity context be added to an existing inbound message context or not.
+     * If not, a new inbound message context is created before the peer entity context is added.
+     * Defaults to false.
+     */
+    @Nonnull private Predicate<ProfileRequestContext> addToExistingInboundMessageContextPredicate;
+    
+    /** Constructor.*/
+    public PrepareOIDCInboundMessageContext() {
+        addToExistingInboundMessageContextPredicate = Predicates.alwaysFalse();
+    }
+    
     @Override
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
@@ -65,6 +83,30 @@ public class PrepareOIDCInboundMessageContext extends AbstractProfileAction {
         }
     }
     
+    /**
+     * Set whether to append any defined subcontexts to the existing inbound message context, or to a new one. 
+     *  
+     * @param flag the flag to set.
+     */
+    public void setAddToExistingInboundMessageContext(final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        addToExistingInboundMessageContextPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
+    
+    /**
+     * Set a predicate to determine whether to append any defined subcontexts to the existing inbound 
+     * message context, or to a new one. 
+     *  
+     * @param predicate the predicate to set.
+     */
+    public void setAddToExistingInboundMessageContextPredicate(
+            @Nonnull final Predicate<ProfileRequestContext> predicate) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        addToExistingInboundMessageContextPredicate = Constraint.isNotNull(predicate, "The predicate can not be null");
+    }
+    
     /**
      * Set the lookup strategy to identify the OP/RP.
      * 
@@ -93,8 +135,19 @@ public class PrepareOIDCInboundMessageContext extends AbstractProfileAction {
     
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        final MessageContext msgCtx = new MessageContext();
-        profileRequestContext.setInboundMessageContext(msgCtx);
+        MessageContext msgCtx = null;
+        if (addToExistingInboundMessageContextPredicate.test(profileRequestContext)) {
+            msgCtx = profileRequestContext.getInboundMessageContext();
+            if (msgCtx == null) {
+                log.warn("{} Profile request context did not contain an inbound message context", getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+                return;
+            }
+        } else {
+            msgCtx = new MessageContext();
+            profileRequestContext.setInboundMessageContext(msgCtx);
+        }
+        
 
         final OIDCPeerEntityContext peerContext = msgCtx.getSubcontext(OIDCPeerEntityContext.class, true);
         peerContext.setIdentifier(identifier);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateIDTokenSignature.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateIDTokenSignature.java
deleted file mode 100644
index 992a6eb..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/ValidateIDTokenSignature.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.authn.oidc.rp.impl;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
-import java.text.ParseException;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.CharStreams;
-import com.nimbusds.jose.shaded.json.JSONArray;
-import com.nimbusds.jose.shaded.json.JSONObject;
-import com.nimbusds.jose.util.JSONObjectUtils;
-
-import net.shibboleth.idp.authn.AbstractAuthenticationAction;
-import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-
-/**
- * An action that verifies the signature of a JWS id_token using the RSA key belonging to the keyID
- * found in the JOSE Header.
- * 
- * <p>The current implementation *requires* the id_token is signed, and *requires* an RSA key type</p>
- * 
- * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
- * @event {@link AuthnEventIds#NO_CREDENTIALS}
- * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class, false) != null</pre>
- * @pre <pre>AuthenticationContext.getSubcontext(OpenIDConnectContext.class, false) != null</pre>
- * @pre <pre>OpenIdConnectContext.getoIDCProviderMetadata() != null</pre>
- * 
- * @since 4.0.0
- */
-public class ValidateIDTokenSignature extends AbstractAuthenticationAction {
-
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateIDTokenSignature.class);
-
-    /** {@inheritDoc} */
-    @Override
-    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext, 
-            @Nonnull final AuthenticationContext authenticationContext) {
-        
-        
-    }
-
-    /**
-     * Parse JWK and RSA public key from the input stream for signature verification.
-     * 
-     * @param is inputstream containing the JWK
-     * @param kid The key ID to be looked up
-     * @return RSA public key as a JSON Object. <code>Null</code> if there is no key
-     * @throws ParseException if parsing fails.
-     * @throws IOException if something unexpected happens.
-     */
-    //TODO could be cached? (or use Nimbus to do this validation as it does cache it). 
-    @Nullable
-    private JSONObject getProviderRSAJWK(@Nonnull final InputStream is, @Nullable final String kid) 
-            throws ParseException, IOException {
-        
-        if (kid == null) {
-            log.warn("No kid defined in the JWT, no signning key can be returned");
-        }
-
-        final StringWriter writer = new StringWriter();
-        CharStreams.copy(new InputStreamReader(is, Charsets.UTF_8), writer);
-
-        final Map<String,Object> json = JSONObjectUtils.parse(writer.toString());
-        final JSONArray keyList = (JSONArray) json.get("keys");
-        if (keyList == null) {            
-            return null;
-        }
-        for (final Object key : keyList) {
-            final JSONObject k = (JSONObject) key;
-            if ("sig".equals(k.get("use")) && "RSA".equals(k.get("kty"))) {
-                if (kid == null || kid.equals(k.get("kid"))) {                                   
-                    return k;
-                }
-            }
-        }        
-        return null;
-    }
-
-}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
index 4939173..3ecae14 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/metadata/impl/OIDCProviderMetadataLookupHandler.java
@@ -1,20 +1,41 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.authn.oidc.rp.metadata.impl;
 
+import java.util.Objects;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
-import org.opensaml.messaging.context.BaseContext;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.handler.AbstractMessageHandler;
 import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.nimbusds.oauth2.sdk.id.Issuer;
 import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.AbstractOIDCEntityContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
 import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
@@ -29,8 +50,14 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
 
 /**
- * Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a OP (issuer), and attaches it with a
- * {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * Handler for inbound OIDC protocol messages that attempts to locate OIDC metadata for a OP (issuer), 
+ * and attaches it with a {@link OIDCMetadataContext} as a child of a pre-existing instance of {@link MessageContext}.
+ * 
+ * <p>
+ * If the optional copy strategy is configured via {@link #setCopyContextStrategy(Function)},
+ * and if that lookup finds an existing metadata context with compatible data (matching the IssuerID),
+ * then its data will be re-used.
+ * </p>
  */
 //TODO This might need a way to set which base class to add the metadata too.
 public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
@@ -40,20 +67,24 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
     
     /** Resolver used to look up OIDC provider information. */
     @NonnullAfterInit private ProviderMetadataResolver providerResolver;
-        
-    /** Strategy used to obtain the issuer id value for the inbound message context. */
-    @NonnullAfterInit private Function<MessageContext,String> issuerIDLookupStrategy;
-    
+
     /** Strategy to resolve the context class to add the resolved metadata too.*/
-    @Nonnull private Function<MessageContext,? extends BaseContext> contextClassLookupStrategy;
+    @Nonnull private Function<MessageContext,? extends AbstractOIDCEntityContext> contextClassLookupStrategy;
+    
+    /** Optional strategy for resolving an existing metadata context from which to copy data. */
+    @Nullable private Function<MessageContext, OIDCProviderMetadataContext> copyContextStrategy;
     
     /** Constructor.*/
     public OIDCProviderMetadataLookupHandler() {
         contextClassLookupStrategy = new ChildContextLookup<>(OIDCPeerEntityContext.class);
     }
     
+    /** Set the context class lookup strategy.
+     * 
+     * @param strategy the strategy.
+     */
     public void setContextClassLookupStrategy(
-            @Nonnull final Function<MessageContext, ? extends BaseContext> strategy) {
+            @Nonnull final Function<MessageContext, ? extends AbstractOIDCEntityContext> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         contextClassLookupStrategy = 
@@ -61,15 +92,14 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
     }
     
     /**
-     * Set the strategy used to locate the client id of the request.
-     * 
-     * @param strategy lookup strategy
+     * Set the optional strategy for resolving an existing metadata context from which to copy data.
+     *
+     * @param strategy the strategy function
      */
-    public void setIssuerIDLookupStrategy(@Nonnull final Function<MessageContext, String> strategy) {
+    public void setCopyContextStrategy(@Nullable final Function<MessageContext, OIDCProviderMetadataContext> strategy) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-        issuerIDLookupStrategy =
-                Constraint.isNotNull(strategy, "IssuerIDLookupStrategy lookup strategy cannot be null");
+
+        copyContextStrategy = strategy;
     }
     
     
@@ -93,38 +123,38 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
        if (providerResolver == null) {
            throw new ComponentInitializationException("IssuerMetadataResolver cannot be null");
        }
-       if (issuerIDLookupStrategy == null) {
-           throw new ComponentInitializationException("IssuerIDLookupStrategy cannot be null");
-       }
+
    }
 
     @Override
     protected void doInvoke(final MessageContext messageContext) throws MessageHandlerException {
         ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
         
-        final BaseContext entityCtx = contextClassLookupStrategy.apply(messageContext);
+        final AbstractOIDCEntityContext entityCtx = contextClassLookupStrategy.apply(messageContext);
 
-        if (entityCtx == null) {
-            log.info("{} OIDC entity context class '{}' missing", getLogPrefix(),
-                    OIDCPeerEntityContext.class);
+        if (entityCtx == null || entityCtx.getIdentifier() == null) {
+            log.info("{} OIDC entity context class '{}' missing or did not contain an issuer identifier", 
+                    getLogPrefix(), AbstractOIDCEntityContext.class);
             return;
         }
         
-        // Resolve issuer id from inbound message
-        final String issuerId = issuerIDLookupStrategy.apply(messageContext);
-        if (issuerId == null) {
-            log.warn("{} No issuer returned from lookup strategy", getLogPrefix());
+        final OIDCProviderMetadataContext existingMetadataCtx = resolveExisting(messageContext,
+                entityCtx.getIdentifier());
+        if (existingMetadataCtx != null) {
+            log.info("{} Resolved existing provider metadata context, re-using it", getLogPrefix());
+            entityCtx.addSubcontext(existingMetadataCtx);
             return;
         }
-        final IssuerIDCriterion issuerCriterion = new IssuerIDCriterion(new Issuer(issuerId));
+        
+        final IssuerIDCriterion issuerCriterion = new IssuerIDCriterion(new Issuer(entityCtx.getIdentifier()));
         final CriteriaSet criteria = new CriteriaSet(issuerCriterion);
         try {
             final OIDCProviderMetadata issuerMetadata = providerResolver.resolveSingle(criteria);
             if (issuerMetadata == null) {
-                log.debug("{} No provider metadata returned for {}",getLogPrefix(), issuerId);
+                log.debug("{} No provider metadata returned for {}",getLogPrefix(), entityCtx.getIdentifier());
                 return;
             }
-            log.debug("{} Found provider metadata for '{}'", getLogPrefix(), issuerId);
+            log.debug("{} Found provider metadata for '{}'", getLogPrefix(), entityCtx.getIdentifier());
             final OIDCProviderMetadataContext context = new OIDCProviderMetadataContext();
             context.setProviderInformation(issuerMetadata);            
             entityCtx.addSubcontext(context);
@@ -132,5 +162,47 @@ public class OIDCProviderMetadataLookupHandler extends AbstractMessageHandler {
             log.error("{} ResolverException thrown during provider metadata lookup", getLogPrefix(), e);
         }
     }
+    
+    /**
+     * Attempt to resolve an existing {@link OIDCProviderMetadataContext} from which to copy.
+     *
+     * <p>
+     * The returned context will always be a fresh parent-less instance, suitable for the caller to
+     * directly store in the current message context.
+     * </p>
+     *
+     * @param messageContext the current message context
+     * @param issuer the identifier of the issuer against which to match
+     *
+     * @return a new instance of {@link SAMLMetadataContext}, or null if one can not be resolved
+     */
+    @Nullable protected OIDCProviderMetadataContext resolveExisting(@Nonnull final MessageContext messageContext,
+            @Nonnull final String issuer) {
+
+        if (copyContextStrategy == null) {
+            return null;
+        }
+
+        final OIDCProviderMetadataContext existing = copyContextStrategy.apply(messageContext);
+        if (existing != null) {
+            if (existing.getProviderInformation() != null) {
+                // Validate that existing data has the same issuer
+                if (Objects.equals(existing.getProviderInformation().getIssuer().getValue(), issuer)) {
+                    log.debug("{} Found an existing and suitable OIDCProviderMetadataContext from which to copy ",
+                            getLogPrefix());
+                    final OIDCProviderMetadataContext copy = new OIDCProviderMetadataContext();
+                    copy.setProviderInformation(existing.getProviderInformation());
+                    return copy;
+                }
+                log.debug("{} Existing OIDCProviderMetadataContext was resolved, but the issuer "
+                        + "did not match the entity context data", getLogPrefix());
+            }
+            log.debug("{} Existing OIDCProviderMetadataContext was resolved, but was missing ProviderInformation "
+                    + "data", getLogPrefix());
+        } else {
+            log.debug("{} No existing OIDCProviderMetadataContext was resolved", getLogPrefix());
+        }
+        return null;
+    }
 
 }
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 1727532..008cf5d 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -35,6 +35,33 @@
         </constructor-arg>
     </bean>
 
+    <bean id="shibboleth.ChildLookup.ProviderMetadataFromProviderContext" 
+    class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
+        c:_0="#{ T(net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext) }" 
+        c:outputType="#{T(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata)}"
+        c:expression="#input.getProviderInformation()" />
+
+
+    <bean id="shibboleth.ChildLookup.OIDCProviderMetadataContextFromPeerEntityContext"
+        parent="shibboleth.Functions.Compose">
+        <constructor-arg name="g">
+            <ref bean="shibboleth.ChildLookup.OIDCProviderMetadataContext" />
+        </constructor-arg>
+        <constructor-arg name="f">
+            <ref bean="shibboleth.ChildLookup.OIDCPeerEntityContext" />
+        </constructor-arg>
+    </bean>
+    
+    <bean id="shibboleth.ChildLookup.OIDCProviderMetadataFromPeerEntityContext"
+        parent="shibboleth.Functions.Compose">
+        <constructor-arg name="g">
+            <ref bean="shibboleth.ChildLookup.ProviderMetadataFromProviderContext" />
+        </constructor-arg>
+        <constructor-arg name="f">
+            <ref bean="shibboleth.ChildLookup.OIDCProviderMetadataContextFromPeerEntityContext" />
+        </constructor-arg>
+    </bean>
+
     <bean id="shibboleth.ChildLookup.OAuth2ClientContextFromOutbound" parent="shibboleth.Functions.Compose">
         <constructor-arg name="g">
             <ref bean="shibboleth.ChildLookup.OAuth2ClientContext" />
@@ -148,6 +175,12 @@
         </property>
     </bean>
 
+    <!-- JWK Cache service for provider keys used inside the trust engine. Will use the same storage engine and context and 
+        the OP?! The key is the URI, so that should be fine. -->
+    <bean id="shibboleth.authn.oidc.rp.RemoteJwkSetCache" class="net.shibboleth.oidc.jwk.RemoteJwkSetCache"
+        p:storage-ref="#{'%{idp.oidc.rp.jwk.StorageService:shibboleth.StorageService}'.trim()}"
+        p:httpClient="#{getObject('shibboleth.oidc.rp.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+        p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.rp.NonBrowser.HttpClientSecurityParameters')}" />
 
 
 
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
index df7f839..4a34e36 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
@@ -1,31 +1,28 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xmlns:p="http://www.springframework.org/schema/p"
-       xmlns:c="http://www.springframework.org/schema/c"
-       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
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" 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 class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
-        p:placeholderPrefix="%{" p:placeholderSuffix="}" />
+
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" p:placeholderPrefix="%{"
+        p:placeholderSuffix="}" />
 
     <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
     <bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
-    
-    
+
+
     <!-- Initial discovery step -->
     <bean id="PropertyDrivenDiscovery" parent="shibboleth.Functions.Constant"
-        c:target="#{'%{idp.authn.oidc.rp.proxyIssuer:}'.trim()}" /> 
-  
+        c:target="#{'%{idp.authn.oidc.rp.proxyIssuer:}'.trim()}" />
+
 
     <!-- Parent beans for indirecting into nested PRC. -->
-    
+
     <bean id="NestedWebFlowMessageHandlerAdaptor" abstract="true"
         class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
@@ -33,91 +30,86 @@
     <bean id="NestedWebFlowProfileActionAdaptor" abstract="true"
         class="net.shibboleth.idp.profile.impl.WebFlowProfileActionAdaptor" scope="prototype"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
-        
-    <bean id="ParentAuthenticiationContextLookup" class="org.opensaml.messaging.context.navigate.ParentContextLookup"
+
+    <bean id="ParentAuthenticiationContextLookup"
+        class="org.opensaml.messaging.context.navigate.ParentContextLookup"
         c:type="net.shibboleth.idp.authn.context.AuthenticationContext" />
-        
-    <!--  Action beans -->
-    
+
+    <!-- Action beans -->
+
     <!-- Explicitly wrapped by a non-nested action adaptor. -->
-    
-     <!-- FIXME (add this back) p:profileId="#{T(net.shibboleth.idp.plugin.oidc.op.config.OIDCCoreProtocolConfiguration).PROFILE_ID}"-->
+
+    <!-- FIXME (add this back) p:profileId="#{T(net.shibboleth.idp.plugin.oidc.op.config.OIDCCoreProtocolConfiguration).PROFILE_ID}" -->
     <bean id="InitializeProxyProfileRequestContext"
-        class="net.shibboleth.idp.authn.proxy.impl.InitializeProxyProfileRequestContext"       
+        class="net.shibboleth.idp.authn.proxy.impl.InitializeProxyProfileRequestContext"
         p:profileId="http://shibboleth.net/ns/profiles/oidc/sso/browser"
-        p:loggingId="%{idp.service.logging.oidcsso:OIDC.SSO}"
-        p:browserProfile="true" />
-        
-   <bean id="FlowStartPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
+        p:loggingId="%{idp.service.logging.oidcsso:OIDC.SSO}" p:browserProfile="true" />
+
+    <bean id="FlowStartPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
         p:fieldExtractors="#{getObject('shibboleth.FlowStartAuditExtractors') ?: getObject('shibboleth.DefaultFlowStartAuditExtractors')}" />
-   
-   
-   <bean id="PrepareOIDCInboundMessageContext"
-            class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PrepareOIDCInboundMessageContext" scope="prototype"
-            p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext">
+
+
+    <bean id="PrepareOIDCInboundMessageContext"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PrepareOIDCInboundMessageContext" scope="prototype"
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext">
         <property name="identiferLookupStrategy">
-           <bean parent="shibboleth.Functions.Compose" c:f-ref="ParentAuthenticiationContextLookup">
-               <constructor-arg name="g">
-                   <bean parent="shibboleth.Functions.Expression" c:expression="#input.getAuthenticatingAuthority()" />
-               </constructor-arg>
-           </bean>
+            <bean parent="shibboleth.Functions.Compose" c:f-ref="ParentAuthenticiationContextLookup">
+                <constructor-arg name="g">
+                    <bean parent="shibboleth.Functions.Expression"
+                        c:expression="#input.getAuthenticatingAuthority()" />
+                </constructor-arg>
+            </bean>
         </property>
     </bean>
-    
-    <bean id="OIDCProviderMetadataLookup" parent="NestedWebFlowMessageHandlerAdaptor"
-        scope="prototype" c:executionDirection="INBOUND">
+
+    <bean id="OIDCProviderMetadataLookup" parent="NestedWebFlowMessageHandlerAdaptor" scope="prototype"
+        c:executionDirection="INBOUND">
         <constructor-arg name="messageHandler">
-            <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.metadata.impl.OIDCProviderMetadataLookupHandler" 
-            scope="prototype">
-               <property name="providerMetadataResolver">
+            <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.metadata.impl.OIDCProviderMetadataLookupHandler"
+                scope="prototype">
+                <property name="providerMetadataResolver">
                     <ref bean="shibboleth.oidc.rp.ProviderMetadataResolver" />
                 </property>
-                <property name="issuerIDLookupStrategy">
-                    <ref bean="shibboleth.oidc.rp.IssuerIDLookupStrategy" />
-                </property>
             </bean>
         </constructor-arg>
-    </bean> 
+    </bean>
+
 
-    
     <bean id="shibboleth.oidc.rp.IssuerIDLookupStrategy"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.metadata.impl.DefaultIssuerIDLookupFunction"
-        scope="prototype" />
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.metadata.impl.DefaultIssuerIDLookupFunction" scope="prototype" />
 
     <bean id="InitializeRelyingPartyContext"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeRelyingPartyContext" scope="prototype"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
-    
-        
+
+
     <bean id="InitializeOutboundMessageContext"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOutboundAuthorizationRequestMessageContext"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        scope="prototype" />
-        
-     <bean id="InitializeOAuth2ClientContext" scope="prototype"
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" scope="prototype" />
+
+    <bean id="InitializeOAuth2ClientContext" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOAuth2ClientContext"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
-    
-       
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
+
     <bean id="SelectRelyingPartyConfiguration"
         class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />    
-        
-    <bean id="SelectProfileConfiguration"
-        class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
-        
+        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
+
+    <bean id="SelectProfileConfiguration" class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration"
+        scope="prototype" p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
     <bean id="PopulateResponseTypeAndModeContext" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PopulateResponseTypeAndModeContext"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
-        
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
     <bean id="AddOIDCAuthenticationRequest" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AddOIDCAuthenticationRequest"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>        
-    
-        
-     <!-- Message Encoder factory is a prototype to allow reuse of the encoders -->
+        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" />
+
+
+    <!-- Message Encoder factory is a prototype to allow reuse of the encoders -->
     <bean id="messageEncoderFactory"
         class="net.shibboleth.oidc.profile.impl.AuthenticationRequestMessageEncoderFactory" scope="prototype"
         c:encoders-ref="shibboleth.authn.oidc.rp.AuthenticationRequestEncoders" />
@@ -129,26 +121,27 @@
     </util:list>
 
     <bean id="HTTPRedirectAuthnRequestEncoder"
-        class="net.shibboleth.oidc.profile.encoder.impl.HTTPRedirectAuthnRequestEncoder" init-method="" scope="prototype"
-        p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
+        class="net.shibboleth.oidc.profile.encoder.impl.HTTPRedirectAuthnRequestEncoder" init-method=""
+        scope="prototype" p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
 
-    <bean id="HTTPPostAuthnRequestEncoder" class="net.shibboleth.oidc.profile.encoder.impl.HTTPPostAuthnRequestEncoder"
-        init-method="" scope="prototype" p:velocityEngine-ref="shibboleth.VelocityEngine"
-        p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
+    <bean id="HTTPPostAuthnRequestEncoder"
+        class="net.shibboleth.oidc.profile.encoder.impl.HTTPPostAuthnRequestEncoder" init-method="" scope="prototype"
+        p:velocityEngine-ref="shibboleth.VelocityEngine" p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
 
 
     <bean id="EncodeMessage" class="org.opensaml.profile.action.impl.EncodeMessage" scope="prototype"
-        p:messageEncoderFactory-ref="messageEncoderFactory" p:httpServletResponse-ref="shibboleth.HttpServletResponse"/>
-        
+        p:messageEncoderFactory-ref="messageEncoderFactory" p:httpServletResponse-ref="shibboleth.HttpServletResponse" />
+
     <!-- TODO: Place holder for message handlers -->
-    <bean id="PreEncodeMessageHandler" class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain" scope="prototype">
+    <bean id="PreEncodeMessageHandler" class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain"
+        scope="prototype">
         <property name="handlers">
             <list>
-               
+
             </list>
         </property>
     </bean>
-    
+
     <!-- Message Decoding -->
     <bean id="messageDecoderFactory" class="net.shibboleth.idp.saml.profile.impl.SpringAwareMessageDecoderFactory">
         <property name="beanMappings">
@@ -158,71 +151,82 @@
             </map>
         </property>
     </bean>
-    
+
     <bean id="OIDCRedirectAuthnResponseDecoder"
-        class="net.shibboleth.oidc.profile.decoding.impl.HTTPRedirectAuthnResponseDecoder" init-method="" scope="prototype"
-        p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
-    
+        class="net.shibboleth.oidc.profile.decoding.impl.HTTPRedirectAuthnResponseDecoder" init-method=""
+        scope="prototype" p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
+
     <bean id="OIDCPostAuthnResponseDecoder"
         class="net.shibboleth.oidc.profile.decoding.impl.HTTPPostAuthnResponseDecoder" init-method="" scope="prototype"
         p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
-    
-    
-    
+
+
+
     <!-- After authentication response -->
-    
+
     <bean id="ValidateExternalAuthenticationContext" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateExternalAuthenticationContext" />        
-     
-    <bean id="ValidateAuthenticationResponseResult" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateAuthenticationResponseResult" 
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
-   
-    <bean id="ValidateResponseStateMatchesRequest" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateExternalAuthenticationContext" />
+
+    <bean id="ValidateAuthenticationResponseResult" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateAuthenticationResponseResult"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
+
+    <bean id="ValidateResponseStateMatchesRequest" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateResponseState"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext" 
-        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
-        
-        
-    <!-- CODE flow beans -->
-    
-    <bean id="InitializeOAuth2ClientAuthenticationContext" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOAuth2ClientAuthenticationContext"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
-        
-    
-    <bean id="ExchangeCodeForAccessToken" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForAccessToken" 
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
+
+    <!-- Create a new OIDCPeerEntityContext and add it to the existing inbound context -->
+    <bean id="AddPeerEntityContextToInboundMessage"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.PrepareOIDCInboundMessageContext" scope="prototype"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+        p:addToExistingInboundMessageContext="true">
+        <property name="identiferLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose" c:f-ref="ParentAuthenticiationContextLookup">
+                <constructor-arg name="g">
+                    <bean parent="shibboleth.Functions.Expression"
+                        c:expression="#input.getAuthenticatingAuthority()" />
+                </constructor-arg>
+            </bean>
+        </property>
+    </bean>
+
+
+    <!-- CODE flow beans -->
+
+    <bean id="InitializeOAuth2ClientAuthenticationContext" parent="NestedWebFlowProfileActionAdaptor"
+        scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.InitializeOAuth2ClientAuthenticationContext" />
+
+
+    <bean id="ExchangeCodeForAccessToken" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExchangeCodeForAccessToken"
         p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
         p:httpClient="#{getObject('shibboleth.authn.oidc.rp.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
         p:httpClientSecurityParameters="#{getObject('shibboleth.authn.oidc.rp.HttpClientSecurityParameters')}"
         p:httpResponseDecoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenResponseDecoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder')}"
-        p:httpRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder')}"/>   
-        
-     <bean id="ValidateOAuthAccessTokenResponse" 
+        p:httpRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.TokenRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder')}" />
+
+    <bean id="ValidateOAuthAccessTokenResponse" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOAuthAccessTokenResponse"
-        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"/>
-     
-     <bean id="ExtractIDTokenFromTokenResponse" scope="prototype"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
+
+    <bean id="ExtractIDTokenFromTokenResponse" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ExtractIDTokenFromResponse"
         p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        p:rawIdTokenLookupStrategy-ref="TokenResponseIDTokenLookupStrategy"/>
-    
-    <bean id="TokenResponseIDTokenLookupStrategy" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.TokenResponseIDTokenLookupStrategy"/>
-    
-    <!-- could these be singletons? --> 
-    <bean id="shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder" scope="prototype" 
+        p:rawIdTokenLookupStrategy-ref="TokenResponseIDTokenLookupStrategy" />
+
+    <bean id="TokenResponseIDTokenLookupStrategy"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.TokenResponseIDTokenLookupStrategy" />
+
+    <!-- could these be singletons? -->
+    <bean id="shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.decoding.impl.DefaultMapResponseDecoder"
-        p:objectMapper-ref="shibboleth.authn.oidc.rp.JSONObjectMapper"/>
-        
-    <bean id="shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder" scope="prototype" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.encoding.impl.NimbusAuthCodeTokenRequestEncoder"/>
-        
-     <!-- Create a default object mapper. Setup should not change once injected -->
+        p:objectMapper-ref="shibboleth.authn.oidc.rp.JSONObjectMapper" />
+
+    <bean id="shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.encoding.impl.NimbusAuthCodeTokenRequestEncoder" />
+
+    <!-- Create a default object mapper. Setup should not change once injected -->
     <bean id="shibboleth.authn.oidc.rp.JSONObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
 
     <bean class="org.springframework.beans.factory.config.MethodInvokingBean"
@@ -244,258 +248,287 @@
         <property name="arguments">
             <bean class="java.text.SimpleDateFormat" c:_0="yyyy-MM-dd'T'HH:mm:ss.SSSZZ" />
         </property>
-    </bean>   
-    
-    
+    </bean>
+
+
     <!-- Process token -->
-    
-    <!-- <bean id="PopulateTokenSignatureSigningParameters"
-        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
-        p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
-        p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver">
-        <property name="securityParametersContextLookupStrategy">
-            <bean parent="shibboleth.Functions.Compose"
-                c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
-                c:f-ref="shibboleth.ChildLookup.RelyingParty" />
-        </property>
-        <property name="existingParametersContextLookupStrategy">
-            <bean parent="shibboleth.Functions.Compose"
-                c:g-ref="shibboleth.ChildLookup.SecurityParameters"
-                c:f-ref="shibboleth.MessageContextLookup.Outbound" />
-        </property>
-    </bean> -->
-    
+
+    <bean id="PopulateIDTokenSignatureValidationParameters" parent="NestedWebFlowProfileActionAdaptor"
+        scope="prototype">
+        <constructor-arg>
+            <bean class="net.shibboleth.oidc.security.impl.GenericPopulateSignatureValidationParameters"
+                p:configurationLookupStrategy-ref="shibboleth.authn.oidc.rp.IDTokenSignatureValidationConfigurationLookup"
+                p:signatureValidationParametersResolver-ref="shibboleth.authn.oidc.rp.IDTokenJwtSignatureValidationParametersResolver" />
+        </constructor-arg>
+    </bean>
+
+    <bean id="shibboleth.authn.oidc.rp.IDTokenJwtSignatureValidationParametersResolver"
+        class="net.shibboleth.oidc.security.impl.OIDCProviderConfigurationSignatureValidationParametersResolver" />
+
+    <bean id="shibboleth.authn.oidc.rp.IDTokenSignatureValidationConfigurationLookup"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.IDTokenSignatureValidationConfigurationLookupFunction"
+        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
+
+
+    <bean id="HandleIDTokenSignature" parent="NestedWebFlowMessageHandlerAdaptor" scope="prototype"
+        c:executionDirection="INBOUND">
+        <constructor-arg>
+            <bean class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain">
+                <property name="handlers">
+                    <list>
+                        <bean
+                            class="net.shibboleth.idp.plugin.authn.oidc.rp.metadata.impl.OIDCProviderMetadataLookupHandler"
+                            scope="prototype" 
+                            p:copyContextStrategy-ref="OutboundOIDCMetadataContextLookup"
+                            p:providerMetadataResolver-ref="shibboleth.oidc.rp.ProviderMetadataResolver" />
+                        <bean class="net.shibboleth.oidc.security.impl.JWTMessageSignatureSecurityHandler"
+                            scope="prototype">
+                            <property name="jwtTokenLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.idp.profile.context.navigate.SpringExpressionContextLookupFunction"
+                                    c:_0="#{ T(org.opensaml.messaging.context.MessageContext) }"
+                                    c:outputType="#{T(com.nimbusds.jwt.SignedJWT)}"
+                                    c:expression="#input.getSubcontext(T(net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext)).getIdToken()" />
+                            </property>
+                            <property name="providerMetadataLookupStrategy">
+                                <ref bean="shibboleth.ChildLookup.OIDCProviderMetadataFromPeerEntityContext" />
+                            </property>
+                        </bean>
+                    </list>
+                </property>
+            </bean>
+        </constructor-arg>
+    </bean>
+
+
+
+    <bean id="OutboundOIDCMetadataContextLookup" parent="shibboleth.Functions.Compose">
+        <constructor-arg name="g">
+            <bean class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+                c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext) }" />
+        </constructor-arg>
+        <constructor-arg name="f">
+            <bean parent="shibboleth.Functions.Compose">
+                <constructor-arg name="g">
+                    <bean class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+                        c:type="#{ T(net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext) }" />
+                </constructor-arg>
+                <constructor-arg name="f">
+                    <bean class="org.opensaml.messaging.context.navigate.MessageContextLookup"
+                        c:direction="OUTBOUND" />
+                </constructor-arg>
+            </bean>
+        </constructor-arg>
+    </bean>
+
+    <!-- these are part of the global system just tmp for now -->
+    <bean id="shibboleth.SignatureValidationConfigurationLookup" lazy-init="true"
+        class="net.shibboleth.idp.profile.config.navigate.SignatureValidationConfigurationLookupFunction"
+        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
+    <bean id="shibboleth.SignatureValidationParametersResolver"
+        class="org.opensaml.xmlsec.impl.BasicSignatureValidationParametersResolver" />
+
     <!-- Default id_token JWT validation wiring. -->
-    
-     <!-- No default cleanup, maybe could be to remove nonce etc. -->
-    <bean id="ValidateIDTokenClaims" scope="prototype"
-       class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
-       p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-       p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
-       p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.idtoken.jwt.claims.CleanUpHook') 
+
+    <!-- No default cleanup, maybe could be to remove nonce etc. -->
+    <bean id="ValidateIDTokenClaims" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+        p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.idtoken.jwt.claims.CleanUpHook') 
            ?: getObject('DefaultCleanupHook')}"
-       p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.idtoken.IDTokenClaimsValidator') 
+        p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.idtoken.IDTokenClaimsValidator') 
            ?: getObject('DefaultIDTokenClaimsValidator')}"
         p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.idtoken.IDTokenLookupStrategy') 
-           ?: getObject('DefaultIDTokenLookupStrategy')}"/>
-        
-    <bean id="DefaultIDTokenLookupStrategy" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy"/>
+           ?: getObject('DefaultIDTokenLookupStrategy')}" />
+
+    <bean id="DefaultIDTokenLookupStrategy"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy" />
 
     <bean id="DefaultIDTokenClaimsValidator"
         class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
         p:claimValidators-ref="IDTokenClaimsValidators" />
-        
+
     <bean id="OIDCProviderMetadataContextChildLookup"
         class="org.opensaml.messaging.context.navigate.ChildContextLookup"
         c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext) }" />
 
-    <bean id="ExpiryClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+    <bean id="ExpiryClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
         p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
 
     <bean id="NotBeforeClaimsValidator"
         class="net.shibboleth.oidc.security.jwt.claims.impl.NotBeforeClaimsValidator"
         p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
-        
-    <bean id="IssuedAtClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
-        p:clockSkew="%{idp.policy.clockSkew:PT1M}"
-        p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+
+    <bean id="IssuedAtClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+        p:clockSkew="%{idp.policy.clockSkew:PT1M}" p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
         p:requiredRule="false" />
 
-    <bean id="IssuerClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+    <bean id="IssuerClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
         p:claimName="iss" p:valueToMatchLookupStrategy-ref="IssuerIDFromOIDCProviderMetadataContextLookupFunction" />
-    
-    <!-- check AZP is required if more than one audience value -->    
-    <bean id="AzpClaimRequiredValidator" 
-         class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
-         <property name="activationCondition">
-            <bean id="MultipleValuesExist" 
+
+    <!-- check AZP is required if more than one audience value -->
+    <bean id="AzpClaimRequiredValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
+        <property name="activationCondition">
+            <bean id="MultipleValuesExist"
                 class="net.shibboleth.oidc.security.jwt.claims.impl.NumberOfClaimValuesActivationCondition"
-                c:claimToCheck="aud"
-                c:numberOfValuesPredicate-ref="ManyValuesPredicate"/>
-         </property>
-         <property name="requiredClaims">
+                c:claimToCheck="aud" c:numberOfValuesPredicate-ref="ManyValuesPredicate" />
+        </property>
+        <property name="requiredClaims">
             <list>
                 <value>azp</value>
             </list>
-         </property>
+        </property>
     </bean>
-    
+
     <!-- TODO, seems like this could be done in XML somehow -->
-    <bean id="ManyValuesPredicate" 
+    <bean id="ManyValuesPredicate"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ManyValuesIntegerComparisonPredicate" />
-        
-    <bean id="AzpClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
-        p:claimName="azp" p:valueToMatchLookupStrategy-ref="ClientIDFromOAuth2ClientContextFunction"> 
-         <property name="activationCondition">
+
+    <bean id="AzpClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+        p:claimName="azp" p:valueToMatchLookupStrategy-ref="ClientIDFromOAuth2ClientContextFunction">
+        <property name="activationCondition">
             <bean id="AzpClaimExistsCondition"
-                class="net.shibboleth.oidc.security.jwt.claims.impl.ClaimExistsActivationCondition"
-                c:claimToCheck="azp"/>
+                class="net.shibboleth.oidc.security.jwt.claims.impl.ClaimExistsActivationCondition" c:claimToCheck="azp" />
         </property>
     </bean>
-        
+
     <bean id="IssuerIDFromOIDCProviderMetadataContextLookupFunction"
         class="net.shibboleth.oidc.profile.logic.IssuerIDFromOIDCProviderMetadataContextLookupFunction"
-        p:oIDCMetadataContextLookupStrategy-ref="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"/>
-        
-    <!-- TODO This bean could be replaced by XML functions? -->
+        p:oIDCMetadataContextLookupStrategy-ref="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy" />
+
+    <!-- TODO This bean could be replaced by XML functions? Could also be from the inbound message context at this point -->
     <bean id="OIDCProviderMetadataContextFromOutboundPeerLookupStrategy"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCProviderMetadataFromOuboundPeerLookupStrategy"/>
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCProviderMetadataFromOuboundPeerLookupStrategy" />
+
+    <bean id="AudienceClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
+        p:audienceLookupStrategy-ref="ClientIDFromOAuth2ClientContextFunction" />
+
 
-    <bean id="AudienceClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator"
-        p:audienceLookupStrategy-ref="ClientIDFromOAuth2ClientContextFunction"/>
-        
-    
     <bean id="ClientIDFromOAuth2ClientContextFunction"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.ClientIDFromOAuth2ClientContextFunction"
-        c:oauth2ClientContextLookupStrategy-ref="shibboleth.ChildLookup.OAuth2ClientContextFromOutbound"/>
-    
-   
-    
-    <bean id="NonceClaimValidator" 
-                class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
-                p:claimName="nonce"
-                p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceLookupStrategy') ?: 
+        c:oauth2ClientContextLookupStrategy-ref="shibboleth.ChildLookup.OAuth2ClientContextFromOutbound" />
+
+
+
+    <bean id="NonceClaimValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+        p:claimName="nonce"
+        p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceLookupStrategy') ?: 
                                 getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy')}"
-                p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceActivationCondition') ?: 
-                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition')}"/>
-    
-    <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.NonceValidationActivationCondition"/>
-        
-    <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AuthenticationRequestNonceClaimLookupStrategy"/>
-    
-    
-    <bean id="OIDCMetadataContextChildLookup"
-        class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+        p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceActivationCondition') ?: 
+                                getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition')}" />
+
+    <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.NonceValidationActivationCondition" />
+
+    <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AuthenticationRequestNonceClaimLookupStrategy" />
+
+
+    <bean id="OIDCMetadataContextChildLookup" class="org.opensaml.messaging.context.navigate.ChildContextLookup"
         c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext) }" />
-        
-    <bean id="OIDCPeerEntityContextChildLookup"
-        class="org.opensaml.messaging.context.navigate.ChildContextLookup"
+
+    <bean id="OIDCPeerEntityContextChildLookup" class="org.opensaml.messaging.context.navigate.ChildContextLookup"
         c:type="#{ T(net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext) }" />
-    
+
     <util:list id="IDTokenClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
         <ref bean="IssuerClaimsValidator" /> <!-- TODO prevent: if it contains additional audiences not trusted by the Client. -->
-        <ref bean="AudienceClaimsValidator" /> 
-        <ref bean="AzpClaimRequiredValidator"/>
-        <ref bean="AzpClaimsValidator"/>       
+        <ref bean="AudienceClaimsValidator" />
+        <ref bean="AzpClaimRequiredValidator" />
+        <ref bean="AzpClaimsValidator" />
         <ref bean="ExpiryClaimsValidator" />
-        <ref bean="IssuedAtClaimsValidator" /> 
+        <ref bean="IssuedAtClaimsValidator" />
         <ref bean="NotBeforeClaimsValidator" />
         <ref bean="NonceClaimValidator" />
         <!-- missing ACR? and auth_time, access_token at_hash. -->
-    </util:list> 
-    
-    
+    </util:list>
+
+
     <bean id="CheckUserInfoRequiredCondition"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoLookupCondition"/>
-        
-    
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoLookupCondition" />
+
+
     <!-- UserInfo endpoint beans -->
-    
-    <bean id="UserInfoEndpointLookup" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.UserInfoEndpointLookup"
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+
+    <bean id="UserInfoEndpointLookup" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.UserInfoEndpointLookup"
         p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
         p:httpClient="#{getObject('shibboleth.authn.oidc.rp.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
         p:httpClientSecurityParameters="#{getObject('shibboleth.authn.oidc.rp.HttpClientSecurityParameters')}"
         p:httpResponseDecoderStrategy="#{getObject('shibboleth.authn.oidc.rp.UserInfoResponseDecoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultUserInfoResponseDecoder')}"
-        p:httpRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.UserInfoRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultUserInfoRequestEncoder')}"/>   
-    
-    
-     <bean id="shibboleth.authn.oidc.rp.DefaultUserInfoResponseDecoder" scope="prototype" 
+        p:httpRequestEncoderStrategy="#{getObject('shibboleth.authn.oidc.rp.UserInfoRequestEncoder') ?: getObject('shibboleth.authn.oidc.rp.DefaultUserInfoRequestEncoder')}" />
+
+
+    <bean id="shibboleth.authn.oidc.rp.DefaultUserInfoResponseDecoder" scope="prototype"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.decoding.impl.DefaultUserInfoResponseDecoder"
-        p:objectMapper-ref="shibboleth.authn.oidc.rp.JSONObjectMapper"/>
-        
-    <bean id="shibboleth.authn.oidc.rp.DefaultUserInfoRequestEncoder" scope="prototype" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.encoding.impl.DefaultUserInfoRequestEncoder"/>
-    
-    
-    <bean id="ValidateUserInfoClaims" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateUserInfoClaims" scope="prototype" 
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
-    
-    
-    <bean id="ProcessEndUserClaims" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ProcessEndUserClaims" scope="prototype" 
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"/>
-        
+        p:objectMapper-ref="shibboleth.authn.oidc.rp.JSONObjectMapper" />
+
+    <bean id="shibboleth.authn.oidc.rp.DefaultUserInfoRequestEncoder" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.encoding.impl.DefaultUserInfoRequestEncoder" />
+
+
+    <bean id="ValidateUserInfoClaims" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateUserInfoClaims"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
+
+
+    <bean id="ProcessEndUserClaims" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ProcessEndUserClaims"
+        scope="prototype" p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
+
     <bean id="CheckUserInfoSignedJWTResponseTypeCondition"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoSignedJWTResponseTypeCondition"/>
-        
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoSignedJWTResponseTypeCondition" />
+
     <bean id="CheckUserInfoEncryptedJWTResponseTypeCondition"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoEncryptedJWTResponseTypeCondition"/>
-    
-    
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoEncryptedJWTResponseTypeCondition" />
+
+
     <!-- UserInfo response JWT validation -->
-    
-    <bean id="ValidateUserInfoToken" scope="prototype"
-       class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
-       p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
-       p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
-       p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.userinfo.jwt.claims.CleanUpHook')}"
-       p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenClaimsValidator') 
+
+    <bean id="ValidateUserInfoToken" parent="NestedWebFlowProfileActionAdaptor" scope="prototype"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
+        p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
+        p:cleanupHook="#{getObject('shibboleth.authn.oidc.rp.userinfo.jwt.claims.CleanUpHook')}"
+        p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenClaimsValidator') 
            ?: getObject('DefaultUserInfoTokenClaimsValidator')}"
         p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenLookupStrategy') 
-           ?: getObject('DefaultUserInfoTokenLookupStrategy')}"/>
-    
+           ?: getObject('DefaultUserInfoTokenLookupStrategy')}" />
+
     <bean id="DefaultUserInfoTokenClaimsValidator"
         class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
         p:claimValidators-ref="UserInfoClaimsValidators" />
-        
-    <bean id="DefaultUserInfoTokenLookupStrategy" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultUserInfoTokenLookupStrategy"/>
+
+    <bean id="DefaultUserInfoTokenLookupStrategy"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultUserInfoTokenLookupStrategy" />
 
     <util:list id="UserInfoClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
         <ref bean="IssuerClaimsValidator" />
-        <ref bean="AudienceClaimsValidator" /> 
-    </util:list> 
-    
-    
-    
+        <ref bean="AudienceClaimsValidator" />
+    </util:list>
+
+
+
     <!-- Final validation and proxy authentication result -->
-    
-    <bean id="ValidateOIDCAuthentication" 
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype" 
-        p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+
+    <bean id="ValidateOIDCAuthentication" parent="NestedWebFlowProfileActionAdaptor"
+        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateOIDCAuthentication" scope="prototype"
         p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup"
         p:responderLookupStrategy-ref="shibboleth.RelyingPartyIdLookup.Simple"
         p:requesterLookupStrategy-ref="shibboleth.ResponderIdLookup.Simple"
         p:attributeFilter-ref="shibboleth.AttributeFilterService"
-        p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"/>
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    <!-- OLD STUFF -->
-    
-    <bean id="ValidateIDTokenSignature"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateIDTokenSignature" />
+        p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
+
 
 
 
+    <!-- OLD STUFF -->
+
+
     <bean id="shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.ForcedAuthenticationActivationCondition"/>
- 
-     
-    <!-- These represent the default set of id_token claims which are **required** by OIDC
-    https://openid.net/specs/openid-connect-core-1_0.html#IDToken -->   
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ForcedAuthenticationActivationCondition" />
+
+
+    <!-- These represent the default set of id_token claims which are **required** by OIDC https://openid.net/specs/openid-connect-core-1_0.html#IDToken -->
     <util:set id="shibboleth.authn.oidc.rp.DefaultRequiredOIDCClaims">
         <value>iss</value>
         <value>sub</value>
@@ -503,5 +536,5 @@
         <value>exp</value>
         <value>iat</value>
     </util:set>
-    
+
 </beans>
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
index 6e5cd49..f69d904 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
@@ -60,6 +60,10 @@
         <evaluate expression="ValidateExternalAuthenticationContext"/>
         <evaluate expression="ValidateAuthenticationResponseResult"/>
         <evaluate expression="ValidateResponseStateMatchesRequest"/>
+        <!-- Add a new OIDCPeerEntityContext to inbound authentication response context 
+        using the original authenticating authority. The OIDC response does not contain an issuer (this is
+        later tested in the id_token) matched against the original provider metadata -->
+        <evaluate expression="AddPeerEntityContextToInboundMessage"/>
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="SwitchOnGrantType" />
     </action-state>
@@ -98,7 +102,8 @@
     
     <!-- TODO claim validation will differ per grant_type -->
     <action-state id="ValidateToken">
-         <!-- <evaluate expression="PopulateTokenSignatureSigningParameters" /> -->
+      <evaluate expression="PopulateIDTokenSignatureValidationParameters" />
+      <evaluate expression="HandleIDTokenSignature" /> 
         <!--  <evaluate expression="PopulateTokenEncryptionParameters" /> -->
          <evaluate expression="ValidateIDTokenClaims" />
          <evaluate expression="'proceed'" />
@@ -128,7 +133,7 @@
      </decision-state>
      
      <action-state id="ValidateSignedUserInfoJWT">
-        <!-- <evaluate expression="PopulateTokenSignatureSigningParameters" /> -->
+       <!--  <evaluate expression="PopulateUserInfoTokenSignatureValidationParameters" /> -->
         <evaluate expression="ValidateUserInfoToken" />
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="ValidateUserInfoClaimsSet" />
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 5feae96..c1fadb1 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -64,8 +64,48 @@
             /> </property> <property name="requestObjectSignatureValidationConfiguration"> <ref bean="#{'%{idp.oidc.rovalid.config:shibboleth.oidc.requestObjectSignatureValidationConfiguration}'.trim()}" 
             /> </property> <property name="tokenEndpointJwtSignatureValidationConfiguration"> <ref bean="#{'%{idp.oidc.rovalid.config:shibboleth.oidc.tokenEndpointJwtSignatureValidationConfiguration}'.trim()}" 
             /> </property> -->
+            <property name="idTokenJwtSignatureValidationConfig"> 
+                <ref bean="#{'%{idp.oidc.rp.rovalid.config:shibboleth.authn.oidc.rp.IDTokenJwtSignatureValidationConfiguration}'.trim()}"/>
+            </property>
     </bean>
-
+    
+    
+     <!-- Configuration for supported algorithms for token endpoint authentication JWT signature validation. -->
+     <!-- TODO This was a parent bean, but as that was not compatible with the new trust engine stuff, I moved to it's own class for now -->
+    <bean id="shibboleth.authn.oidc.rp.IDTokenJwtSignatureValidationConfiguration" 
+        class="net.shibboleth.oidc.security.impl.BasicSignatureValidationConfiguration"
+        p:signatureTrustEngine-ref="ExplicitKeySignedJWTTrustEngine">
+        <!-- <property name="signatureAlgorithms">
+            <list>
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_384" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_512" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_ES_256" />
+                <util:constant 
+                     static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_ES_384" /> 
+                <util:constant 
+                     static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_ES_512" /> 
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_384" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_512" />
+            </list>
+        </property> -->
+    </bean>
+    
+    <bean id="ExplicitKeySignedJWTTrustEngine"
+        class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine"
+        c:resolver-ref="OIDCProviderMetadataCredentialResolver"/>
+    
+    <bean id="OIDCProviderMetadataCredentialResolver" 
+        class="net.shibboleth.oidc.security.impl.ProviderMetadataCredentialResolver"
+        p:remoteJwkSetCache-ref="shibboleth.authn.oidc.rp.RemoteJwkSetCache"/>
 
 
 </beans>
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index e49611f..3640245 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -28,6 +28,7 @@ import java.util.Map;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.TrustAllStrategy;
@@ -36,6 +37,8 @@ import org.apache.http.ssl.SSLContextBuilder;
 import org.junit.Test;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -46,6 +49,7 @@ import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 import org.springframework.webflow.execution.FlowExecution;
 import org.springframework.webflow.test.MockFlowBuilderContext;
 
+import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.EncryptionMethod;
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JOSEObjectType;
@@ -84,7 +88,6 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
-import net.shibboleth.idp.plugin.authn.oidc.rp.config.StorageServiceBackedClientAuthenticationLookupStrategy;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.ResponseTypeAndModeContext;
@@ -94,10 +97,16 @@ import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.relyingparty.RelyingPartyConfiguration;
 import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCSecurityConfiguration;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.impl.BasicSignatureValidationConfiguration;
+import net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
 import okhttp3.mockwebserver.MockResponse;
 import okhttp3.mockwebserver.MockWebServer;
 import okhttp3.tls.HandshakeCertificates;
@@ -111,6 +120,8 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
     private final String RP_ALLOWED_ORIGINS = "https://localhost";
     
     private static final String CLIENT_ID = "demo_rp";
+    
+    private static final String ID_TOKEN_HMAC_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
 
     /**
      * Example of good provider metadata. Endpoints are localhost to support the 
@@ -306,7 +317,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
                 .build();
         payload.getClaims().forEach((k,v) -> log.debug("{}:{}",k,v));
         final var signedJWT = new SignedJWT(header,payload);
-        signedJWT.sign(new MACSigner("Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$"));
+        signedJWT.sign(new MACSigner(ID_TOKEN_HMAC_SECRET));
         final String accessTokenSerialized = "{\n"
         + "  \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
         + "  \"token_type\": \"Bearer\",\n"
@@ -614,6 +625,31 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
        
     }
     
+    private OIDCSecurityConfiguration createSecurityConfigAndValidationParamsForHMAC(
+            @Nonnull final byte[] secret, @Nonnull final String algo) {
+
+        final var securityConfig = new OIDCSecurityConfiguration();
+        final var sigValConfig = new BasicSignatureValidationConfiguration<SignedJWT>();
+        final var credResolver = new CredentialResolver() {
+            
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                final var cred = new BasicJWKCredential();
+                cred.setAlgorithm(Algorithm.parse(algo));
+                cred.setSecretKey(new SecretKeySpec(secret, algo));
+                return cred;
+            }
+            
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        };
+        sigValConfig.setSignatureTrustEngine(new ExplicitKeySignedJWTTrustEngine(credResolver));
+        securityConfig.setIdTokenJwtSignatureValidationConfig(sigValConfig);
+        return securityConfig;
+    }
+    
     @Test 
     public void testAuthnFlowFromAuthorizationCallback_UsingSignedJWTUserInfoResponse() throws Exception {
         
@@ -653,6 +689,9 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         final RelyingPartyContext partyContext = new RelyingPartyContext();
         final OIDCAuthorizationConfiguration partyConfig = new OIDCAuthorizationConfiguration();        
         partyContext.setProfileConfig(partyConfig);
+        
+        partyConfig.setSecurityConfiguration(createSecurityConfigAndValidationParamsForHMAC(
+                ID_TOKEN_HMAC_SECRET.getBytes(), "HS256"));
         partyConfig.setClientAuthenticationLookupStrategy(p ->
             new ClientSecretBasic(new ClientID(CLIENT_ID), new Secret("secret")));
                 
@@ -660,9 +699,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         rPartyConfig.setResponderId("http://idp.example.com/");
         partyContext.setConfiguration(rPartyConfig);
         nestPrc.addSubcontext(partyContext);
-        
-       
-       
+
         // Setup outbound context
         final MessageContext outMsgCtx = new MessageContext();        
         outMsgCtx.setMessage(createAuthenticationRequest());        
@@ -828,10 +865,12 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         // Add under nest PRC
         final RelyingPartyContext partyContext = new RelyingPartyContext();
         final OIDCAuthorizationConfiguration partyConfig = new OIDCAuthorizationConfiguration();  
-        partyConfig.setClientAuthenticationLookupStrategy(new StorageServiceBackedClientAuthenticationLookupStrategy());
         partyContext.setProfileConfig(partyConfig);
         partyConfig.setClientAuthenticationLookupStrategy(p ->
                 new ClientSecretBasic(new ClientID(CLIENT_ID), new Secret("secret")));
+        final RelyingPartyConfiguration rPartyConfig = new RelyingPartyConfiguration();
+        rPartyConfig.setResponderId("http://idp.example.com/");
+        partyContext.setConfiguration(rPartyConfig);
         nestPrc.addSubcontext(partyContext);
        
         // Setup outbound context
diff --git a/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml b/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
index 8fbf822..ecf2f28 100644
--- a/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
+++ b/idp-oidc-rp-impl/src/test/resources/conf/test-relying-party-system.xml
@@ -9,13 +9,13 @@
 
     default-init-method="initialize" default-destroy-method="destroy">
 
-    <!-- TODO: left this bean out of the tests
-      p:defaultSecurityConfiguration-ref="%{idp.security.config:shibboleth.DefaultSecurityConfiguration}" -->
+    <!-- removed, but I do not know what the default should be in this case
+    p:defaultSecurityConfiguration-ref="%{idp.security.config:shibboleth.DefaultSecurityConfiguration}" -->
     <bean class="net.shibboleth.idp.relyingparty.impl.DefaultRelyingPartyConfigurationResolver"
         p:unverifiedConfiguration-ref="shibboleth.UnverifiedRelyingParty"
         p:defaultConfiguration-ref="shibboleth.DefaultRelyingParty"
         p:relyingPartyConfigurations-ref="shibboleth.RelyingPartyOverrides"
-       
+        
         p:signingCredentials="#{getObject('shibboleth.SigningCredentials')}"
         p:encryptionCredentials="#{getObject('shibboleth.EncryptionCredentials')}" />
 
@@ -47,7 +47,7 @@
     </util:list>
    
     
-        <!-- 
+    <!-- 
     Map clients to appropriate client authentication - only supports client_secret_basic and client_secret_post
     -->
     
diff --git a/pom.xml b/pom.xml
index 9cef199..618e747 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,10 +16,10 @@
 
     <properties>
         <idp.groupId>net.shibboleth.idp</idp.groupId>
-        <idp.version>4.2.0-SNAPSHOT</idp.version>
+        <idp.version>4.2.2-SNAPSHOT</idp.version>
         <opensaml.groupId>org.opensaml</opensaml.groupId>
-        <opensaml.version>4.2.0-SNAPSHOT</opensaml.version>
-        <oidc.common.version>2.0.0-SNAPSHOT</oidc.common.version>
+        <opensaml.version>4.2.1-SNAPSHOT</opensaml.version>
+        <oidc.common.version>2.1.0-SNAPSHOT</oidc.common.version>
         <checkstyle.configLocation>${project.basedir}/checkstyle.xml</checkstyle.configLocation>
     </properties>
 

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


More information about the commits mailing list