[java-idp-plugin-oidc-rp] branch main updated: Improve client credential handling and wire into client_auth action

Phil Smart philip.smart at jisc.ac.uk
Fri May 20 12:59:45 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=af61cba4154095ab00866314df6324da4eb6fef0

The following commit(s) were added to refs/heads/main by this push:
     new af61cba  Improve client credential handling and wire into client_auth action
af61cba is described below

commit af61cba4154095ab00866314df6324da4eb6fef0
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri May 20 13:59:36 2022 +0100

    Improve client credential handling and wire into client_auth action
    
     - Wire up new CriterionCredentialResolver
---
 ...atureValidationConfigurationLookupFunction.java |   8 +-
 .../rp/storage/ClientAuthenticationDetails.java    |   3 +
 idp-oidc-rp-impl/pom.xml                           |   5 +
 .../DefaultClientAuthenticationLookupStrategy.java |   3 +
 .../config/DefaultClientSecretLookupStrategy.java  | 146 +++++++++++++++++++
 ...nitializeOAuth2ClientAuthenticationContext.java | 114 ++++++++++++++-
 .../oidc-relying-party-authn-beans.xml             |  21 ++-
 .../oidc-relying-party-authn-flow.xml              |   7 +-
 .../idp/service/relying-party/postconfig.xml       |  57 ++++----
 .../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java  | 159 +++++++++++++++++++--
 .../resources/conf/test-relying-party-system.xml   |  12 +-
 11 files changed, 479 insertions(+), 56 deletions(-)

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
index c4856ff..e29535f 100644
--- 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
@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
+import com.nimbusds.jwt.SignedJWT;
+
 import net.shibboleth.idp.profile.config.ProfileConfiguration;
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
@@ -41,7 +43,7 @@ import net.shibboleth.oidc.security.SignatureValidationConfiguration;
  * </p>
  */
 public class IDTokenSignatureValidationConfigurationLookupFunction 
-            extends AbstractRelyingPartyLookupFunction<List<SignatureValidationConfiguration>> {
+            extends AbstractRelyingPartyLookupFunction<List<SignatureValidationConfiguration<SignedJWT>>> {
 
     /** A resolver for default security configurations. */
     @Nullable
@@ -59,9 +61,9 @@ public class IDTokenSignatureValidationConfigurationLookupFunction
     /** {@inheritDoc} */
     @Override
     @Nullable
-    public List<SignatureValidationConfiguration> apply(@Nullable final ProfileRequestContext input) {
+    public List<SignatureValidationConfiguration<SignedJWT>> apply(@Nullable final ProfileRequestContext input) {
 
-        final List<SignatureValidationConfiguration> configs = new ArrayList<>();
+        final List<SignatureValidationConfiguration<SignedJWT>> configs = new ArrayList<>();
 
         final RelyingPartyContext rpc = getRelyingPartyContextLookupStrategy().apply(input);
         if (rpc != null) {
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/storage/ClientAuthenticationDetails.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/storage/ClientAuthenticationDetails.java
index b8cbdd4..fa12f6c 100644
--- a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/storage/ClientAuthenticationDetails.java
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/storage/ClientAuthenticationDetails.java
@@ -10,6 +10,9 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
 /** A bean to hold client_authentication registration details.*/
+//TODO: this is not a storage system bean, the json properties are not needed.
+//TODO we no longer use this, remove!
+ at Deprecated
 @Immutable
 public class ClientAuthenticationDetails {
     
diff --git a/idp-oidc-rp-impl/pom.xml b/idp-oidc-rp-impl/pom.xml
index 6ad016c..5e68638 100644
--- a/idp-oidc-rp-impl/pom.xml
+++ b/idp-oidc-rp-impl/pom.xml
@@ -153,6 +153,11 @@
             <artifactId>idp-profile-impl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-profile-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>net.shibboleth.idp</groupId>
             <artifactId>idp-profile-api</artifactId>
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategy.java
index cefdee5..1b0944b 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategy.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategy.java
@@ -47,8 +47,11 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
 /**
  * A strategy that produces a client authentication method either directly from the information supplied, 
  * or derived from a lookup strategy. 
+ * 
+ * @deprecated see see InitializeOAuth2ClientAuthenticationContext
  */
 @ThreadSafeAfterInit
+ at Deprecated 
 public class DefaultClientAuthenticationLookupStrategy extends AbstractClientAuthenticationLookupStrategy {
     
     /** A fixed client_id to use.*/
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientSecretLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientSecretLookupStrategy.java
new file mode 100644
index 0000000..f3d3f66
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientSecretLookupStrategy.java
@@ -0,0 +1,146 @@
+/*
+ * 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;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * A strategy that produces a client_secret either directly from the one supplied, or derived from the 
+ * lookup strategy. 
+ */
+//TODO secret could be private key
+ at ThreadSafe
+public class DefaultClientSecretLookupStrategy extends AbstractIdentifiableInitializableComponent
+                    implements Function<ProfileRequestContext, String> {
+        
+    /** 
+     * A fixed client_secret to use over any injected strategy to locate one. 
+     * Must be UTF-8 encoded.
+     */
+    @Nullable private String clientSecret;
+    
+    /** The strategy used to lookup or create the {@link OAuth2ClientContext}.*/
+    @Nonnull private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
+    
+    /** Map of client_id to client_secret. Can be {@literal null} if a fixed client_id are secret are used.*/
+    @Nullable @NotLive private Map<String, String> clientIdToClientSecretMap;
+
+    /**
+     * Constructor.
+     */
+    public DefaultClientSecretLookupStrategy() {     
+        oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class).compose(
+                new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
+                        new OutboundMessageContextLookup()));
+    }
+    
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (clientSecret == null && clientIdToClientSecretMap == null) {
+            throw new ComponentInitializationException("Must supply either a fixed client_secret or a "
+                    + "client_id to client_secret map");
+        }
+    }
+    
+    /**
+     * Set the client_id to client_secret map.
+     * 
+     * @param map the map of client_id to client_secret details
+     */
+    public void setClientIdToClientSecretMap(@Nullable final Map<String, String> map) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        if (map == null) {
+            clientIdToClientSecretMap = Collections.emptyMap();
+        } else {
+            clientIdToClientSecretMap = Collections.unmodifiableMap(map);
+        }
+    }
+    
+    /**
+     * Set the strategy to lookup the {@link OAuth2ClientContext} 
+     * from the {@link ProfileRequestContext}.
+     * 
+     * @param strgy the strategy.
+     */
+    public void setOAuth2ClientContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, OAuth2ClientContext> strgy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        oauth2ClientContextLookupStrategy = Constraint.isNotNull(strgy, 
+                "OAuth2 client context lookup strategy cannot be null");
+    }
+    
+    /**
+     * Set the client_secret. Must be UTF-8 encoded.
+     * 
+     * @param secret the client_secret
+     */
+    public void setClientSecret(@Nullable final String secret) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        clientSecret = secret;
+    }
+
+    @Override
+    @Nullable public String apply(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        // Use supplied client_id first
+        if (clientSecret != null) {
+            return clientSecret;
+        } 
+        // Else pull it from the map
+        final OAuth2ClientContext clientCtx = oauth2ClientContextLookupStrategy.apply(profileRequestContext);
+        if (clientCtx == null || StringSupport.trimOrNull(clientCtx.getClientId()) == null) {
+            return null;
+        }
+        final String secret = 
+                clientIdToClientSecretMap.get(clientCtx.getClientId());
+        
+        if (secret!= null && secret.length() > 0) {
+            return secret;
+        }
+        return null;
+    }
+
+}
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 e9d564a..804b867 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
@@ -17,20 +17,31 @@
 
 package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
 
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.crypto.SecretKey;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
+import org.opensaml.security.credential.Credential;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.id.ClientID;
 
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.profile.AbstractProfileAction;
@@ -38,6 +49,7 @@ import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.authn.context.OAuth2ClientAuthenticationContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ExpiringJWKCredential;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -95,6 +107,8 @@ public class InitializeOAuth2ClientAuthenticationContext extends AbstractProfile
      */
     public void setRelyingPartyContextLookupStrategy(
             @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
         relyingPartyContextLookupStrategy =
                 Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
     }
@@ -149,17 +163,107 @@ public class InitializeOAuth2ClientAuthenticationContext extends AbstractProfile
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         super.doExecute(profileRequestContext);
         
-        final ClientAuthentication clientAuth = profileConfiguration.getClientAuthentication(profileRequestContext);
-        
-        if (clientAuth == null) {
+        final String clientAuthMethod = 
+                profileConfiguration.getClientAuthenticationMethod(profileRequestContext);
+        if (clientAuthMethod == null) {
             log.error("{} No client authentication mode found from profile configuration", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
             return;
         }
         
-        oauth2ClientAuthenticationContext.setClientAuthentication(clientAuth);   
+        final String clientId = 
+                profileConfiguration.getClientId(profileRequestContext);
+        if (clientId == null) {
+            log.error("{} No client_id found from profile configuration", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+            return;
+        }
+        
+        final Credential clientCredential = 
+                profileConfiguration.getClientCredential(profileRequestContext);
+        if (clientCredential == null) {
+            log.error("{} No client credential found from profile configuration", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+            return;
+        }
+        
+        final ClientAuthentication clientAuthentication = 
+                constructClientAuthentication(clientId, clientAuthMethod, clientCredential);
+        
+        if (clientAuthentication == null) {
+            log.error("{} No client authentication could be constructed", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+            return;
+        }
+
+        oauth2ClientAuthenticationContext.setClientAuthentication(clientAuthentication);   
         log.debug("{} Initialized OAuth2 Client Authentication Context: Found client authentication mode "
-                + "'{}' for client '{}'",getLogPrefix(), clientAuth.getMethod(), clientAuth.getClientID());
+                + "'{}' for client '{}'",getLogPrefix(), clientAuthentication.getMethod(), 
+                clientAuthentication.getClientID());
+    }
+    
+    /**
+     * Construct the client authentication from the given client authentication record.
+     * 
+     * @param clientId the client_id
+     * @param tokenEndpointAuthMethod the token endpoint authentication method
+     * @param clientCredential the client credential
+     * 
+     * @return the constructed client authentication
+     */
+    @Nullable protected ClientAuthentication constructClientAuthentication(
+            @Nonnull final String clientId, @Nonnull final String tokenEndpointAuthMethod,
+            @Nonnull final Credential clientCredential) {
+        
+        // TODO support private key jwt
+        if (clientCredential.getSecretKey() == null) {
+            log.warn("{} Client credential is not a symmetric key, only client_secret currently supported to"
+                    + "construct client authentication",getLogPrefix());
+            return null;
+        }
+        Duration secretExpiresAt = Duration.ZERO;
+        if (clientCredential instanceof ExpiringJWKCredential) {
+            secretExpiresAt = ((ExpiringJWKCredential)clientCredential).getCredentialExpiresAt();
+        }
+        
+        final String secretKeyConverted = convertSecretKeyToString(clientCredential.getSecretKey());
+        if (secretKeyConverted == null) {
+            log.warn("{} Secret key is null, unable to construct client authentication",getLogPrefix());
+            return null;
+        }
+        final Secret secret = secretExpiresAt.toSeconds() == 0 ? 
+                new Secret(secretKeyConverted) :
+            new Secret(secretKeyConverted, Date.from(Instant.ofEpochSecond(secretExpiresAt.toSeconds())));
+        
+
+        if (secret.expired()) {
+            log.warn("{} Client secret has expired for client '{}'", getLogPrefix(), clientId);
+            return null;
+        }
+        
+        final ClientAuthenticationMethod method = new ClientAuthenticationMethod(tokenEndpointAuthMethod);
+        if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
+            return new ClientSecretBasic(new ClientID(clientId), secret);
+        } else if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
+            return new ClientSecretPost(new ClientID(clientId), secret);
+        }  
+        log.warn("{}: Client authentication method '{}' not supported for client '{}'", getLogPrefix(), 
+                tokenEndpointAuthMethod, clientId);
+        return null;
+        
+    }
+    
+    /**
+     * Convert the encoded byte array representing the secret into a UTF-8 String.
+     * 
+     * @param key the key to convert
+     * @return the UTF-8 encoded string value of the secret. 
+     */
+    @Nullable private String convertSecretKeyToString(@Nullable final SecretKey key) {
+        if (key == null || key.getEncoded() == null) {
+            return null;
+        }
+        return new String(key.getEncoded(),StandardCharsets.UTF_8);
     }
     
     
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 b544ef6..62a1059 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
@@ -251,7 +251,25 @@
     </bean>
 
 
-    <!-- Process token -->
+    <!-- ID_TOKEN Decryption -->
+    
+     <bean id="PopulateIDTokenDecryptionParameters" parent="NestedWebFlowProfileActionAdaptor" scope="prototype">
+        <constructor-arg>
+            <bean class="org.opensaml.profile.action.impl.PopulateDecryptionParameters"
+                p:configurationLookupStrategy-ref="shibboleth.authn.oidc.rp.DecryptionConfigurationLookup"
+                p:decryptionParametersResolver-ref="shibboleth.DecryptionParametersResolver" />
+        </constructor-arg>
+    </bean>
+         
+        <!-- FIXME: this bean already exists in security-system -->
+    <bean id="shibboleth.authn.oidc.rp.DecryptionConfigurationLookup" lazy-init="true"
+        class="net.shibboleth.idp.profile.config.navigate.DecryptionConfigurationLookupFunction"
+        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
+        
+    <bean id="shibboleth.DecryptionParametersResolver"
+        class="org.opensaml.xmlsec.impl.BasicDecryptionParametersResolver" />
+        
+    <!-- ID_TOKEN Signature Validation -->
 
     <bean id="PopulateIDTokenSignatureValidationParameters" parent="NestedWebFlowProfileActionAdaptor"
         scope="prototype">
@@ -269,7 +287,6 @@
         class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.IDTokenSignatureValidationConfigurationLookupFunction"
         p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyConfigurationResolver" />
 
-
     <!-- TODO decryption as well? -->
     <bean id="HandleIDTokenValidation" parent="NestedWebFlowMessageHandlerAdaptor" scope="prototype"
         c:executionDirection="INBOUND">
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 8a2a9b9..5d45e82 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
@@ -59,6 +59,7 @@
     </view-state>
 
     <action-state id="ValidateResponse">
+        <!-- PopulateClientTLSValidationParameters? -->
         <evaluate expression="ValidateExternalAuthenticationContext" />
         <evaluate expression="ValidateAuthenticationResponseResult" />
         <evaluate expression="ValidateResponseStateMatchesRequest" />
@@ -107,7 +108,7 @@
 
     <!-- TODO claim validation will differ per grant_type -->
     <action-state id="ValidateToken">
-        <!--  <evaluate expression="PopulateTokenEncryptionParameters" /> -->
+        <evaluate expression="PopulateIDTokenDecryptionParameters" />
         <evaluate expression="PopulateIDTokenSignatureValidationParameters" />
         <evaluate expression="HandleIDTokenValidation" />
 
@@ -142,7 +143,7 @@
 
     <action-state id="ValidateSignedUserInfoJWT">
         <!-- <evaluate expression="PopulateUserInfoTokenSignatureValidationParameters" /> -->
-        
+        <!-- SIGNATURE CHECK! -->
         <evaluate expression="ValidateUserInfoToken" />
         <evaluate expression="'proceed'" />
         <transition on="proceed" to="ValidateUserInfoClaimsSet" />
@@ -153,7 +154,7 @@
         <!-- <evaluate expression="PopulateTokenEncryptionParameters" /> -->
         <evaluate expression="ValidateUserInfoToken" /> <!-- Will die if not decrypted properly first -->
         <evaluate expression="'proceed'" />
-        <transition on="proceed" to="ValidateUserInfoClaimsSet" />
+        <transition on="proceed" to="ValidateSignedUserInfoJWT" />
     </action-state>
 
     <action-state id="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 c1fadb1..cc799db 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
@@ -12,7 +12,7 @@
     <!-- OIDC RP Profile Configurations. -->
 
     <bean id="AbstractOIDCProfile" abstract="true"
-        p:securityConfiguration-ref="%{idp.security.authn.oidc.rp.config:shibboleth.oidc.DefaultSecurityConfiguration}" />
+        p:securityConfiguration-ref="%{idp.security.authn.oidc.rp.config:shibboleth.authn.oidc.rp.DefaultSecurityConfiguration}" />
 
     <bean id="AbstractOIDCSSOProfile" parent="AbstractOIDCProfile" abstract="true" p:issuer-ref="issuer"
         p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
@@ -23,6 +23,7 @@
         p:alwaysIncludedAttributes="%{idp.authn.oidc.rp.alwaysIncludedAttributes:}" />
 
     <!-- FIXME This will NEED a new ID and possibly class. If not, the OP plugin and RP plugin can not be installed together -->
+    <!--  Only load the default client_id and client_secret if discovery is disabled -->
     <bean id="OIDC.SSO" parent="AbstractOIDCSSOProfile" lazy-init="true"
         class="net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration"
         p:httpRequestMethod="%{idp.authn.oidc.rp.httpRequestMethod:GET}"
@@ -30,32 +31,15 @@
         p:encodeConsentInTokens="%{idp.authn.oidc.rp.encodeConsentInTokens:false}"
         p:encodedAttributes="%{idp.authn.oidc.rp.encodedAttributes:%{idp.oidc.embeddedAttributes:}}"
         p:deniedUserInfoAttributes="%{idp.authn.oidc.rp.deniedUserInfoAttributes:}"
-        p:clientIdLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.ClientIdentifierLookupStrategy') ?: getObject('shibboleth.authn.oidc.rp.DefaultClientIdentifierLookupStrategy')}"
-        p:clientAuthenticationLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.ClientAuthenticationLookupStrategy') ?: getObject('shibboleth.authn.oidc.rp.DefaultClientAuthenticationLookStrategy')}" />
+        p:clientId="#{%{idp.authn.oidc.rp.discoveryRequired:false} == true ? null : '%{idp.authn.oidc.rp.client.clientId:}'}"
+        p:clientCredential="#{%{idp.authn.oidc.rp.discoveryRequired:false} == true ? {null} : getObject('shibboleth.authn.oidc.rp.DefaultCredential')}"
+        p:clientAuthenticationMethod="%{idp.authn.oidc.rp.clientAuthenticationMethod:client_secret_basic}"/>
     
-    <bean id="shibboleth.authn.oidc.rp.DefaultClientAuthenticationLookStrategy"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.DefaultClientAuthenticationLookupStrategy"
-        p:clientId="%{idp.authn.oidc.rp.client.clientId:#{null}}"
-        p:clientSecret="%{idp.authn.oidc.rp.client.clientSecret:#{null}}"
-        p:clientAuthenticationMethod="%{idp.authn.oidc.rp.client.clientAuthenticationMethod:client_secret_basic}"
-        p:clientSecretExpiresAt="%{idp.authn.oidc.rp.client.clientSecretExpiresAt:PT0S}"
-        p:clientIdToClientAuthenticationMap="#{getObject('shibboleth.authn.oidc.rp.ClientIdToClientAuthenticationMap')}"/>
-    
-    <bean id="shibboleth.authn.oidc.rp.DefaultClientIdentifierLookupStrategy" lazy-init="true"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.DefaultClientIdentifierLookupStrategy" 
-        c:clientId="%{idp.authn.oidc.rp.client.clientId:#{null}}"
-        c:issuerToClientIdMap="#{getObject('shibboleth.authn.oidc.rp.IssuerToClientIdMap')}"
-        c:providerMetadataLookupStrategy-ref="shibboleth.ChildLookup.OIDCProviderMetadataContextFromOutbound"/>
-    
-    <!-- Client Authentication parent bean which defaults secrets to not expire -->
-    <bean id="shibboleth.authn.oidc.rp.ClientAuthenticationDetails"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.storage.ClientAuthenticationDetails" abstract="true"
-        c:clientSecretExpiresAt="0" />
 
     <!-- Security Configuration Defaults. These settings establish the default security configurations for signatures and 
         loads the default credentials used. -->
 
-    <bean id="shibboleth.oidc.DefaultSecurityConfiguration"
+    <bean id="shibboleth.authn.oidc.rp.DefaultSecurityConfiguration"
         class="net.shibboleth.oidc.profile.config.OIDCSecurityConfiguration">
         <!-- Add these back were appropriate -->
         <!-- <property name="signatureSigningConfiguration"> <ref bean="#{'%{idp.oidc.signing.config:shibboleth.oidc.SigningConfiguration}'.trim()}" 
@@ -69,6 +53,17 @@
             </property>
     </bean>
     
+   <!-- For developers to override per RP config --> 
+   <bean id="shibboleth.authn.oidc.rp.ExpiringJWKCredential" abstract="true"
+        class="net.shibboleth.oidc.security.impl.BasicExpiringJWTStaticCredentialFactoryBean"
+        p:credentialExpiresAt="%{idp.authn.oidc.rp.client.clientSecretExpiresAt:PT0S}"/>
+        
+   <bean id="shibboleth.authn.oidc.rp.DefaultCredential"
+        parent="shibboleth.authn.oidc.rp.ExpiringJWKCredential"
+        p:secret="%{idp.authn.oidc.rp.client.clientSecret:#{null}}"
+        p:keyNames="defaultPropertiesClientSecret"/>
+        
+    
     
      <!-- 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 -->
@@ -99,13 +94,23 @@
         </property> -->
     </bean>
     
+    <bean id="defaultSignedJWTCredentialResolver" class="org.opensaml.security.credential.impl.ChainingCredentialResolver">
+        <constructor-arg>
+            <list>
+               <bean id="OIDCProviderMetadataCredentialResolver" 
+                        class="net.shibboleth.oidc.security.impl.ProviderMetadataCredentialResolver"
+                        p:remoteJwkSetCache-ref="shibboleth.authn.oidc.rp.RemoteJwkSetCache"/>
+                 <bean id="CriterionCredentialResolver" 
+                        class="net.shibboleth.oidc.security.impl.CriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>
+    
     <bean id="ExplicitKeySignedJWTTrustEngine"
         class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine"
-        c:resolver-ref="OIDCProviderMetadataCredentialResolver"/>
+        c:resolver-ref="defaultSignedJWTCredentialResolver"/>
+    
     
-    <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 3640245..e5fe1d2 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
@@ -20,6 +20,8 @@ package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
 import java.time.Instant;
 import java.util.Date;
 import java.util.HashMap;
@@ -39,6 +41,8 @@ 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.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.DecryptionConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -49,6 +53,7 @@ import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 import org.springframework.webflow.execution.FlowExecution;
 import org.springframework.webflow.test.MockFlowBuilderContext;
 
+import com.google.common.base.Enums;
 import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.EncryptionMethod;
 import com.nimbusds.jose.JOSEException;
@@ -59,6 +64,7 @@ import com.nimbusds.jose.JWEObject;
 import com.nimbusds.jose.JWSAlgorithm;
 import com.nimbusds.jose.JWSHeader;
 import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.DirectEncrypter;
 import com.nimbusds.jose.crypto.ECDSASigner;
 import com.nimbusds.jose.crypto.MACSigner;
 import com.nimbusds.jose.crypto.RSAEncrypter;
@@ -99,12 +105,17 @@ 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.BasicExpiringJWKCredential;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.impl.BasicExpiringJWTStaticCredentialFactoryBean;
 import net.shibboleth.oidc.security.impl.BasicSignatureValidationConfiguration;
 import net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine;
+import net.shibboleth.oidc.security.impl.JWSAssemblyUtils;
 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.logic.FunctionSupport;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 import okhttp3.mockwebserver.MockResponse;
@@ -121,7 +132,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
     
     private static final String CLIENT_ID = "demo_rp";
     
-    private static final String ID_TOKEN_HMAC_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
+    private static final String CLIENT_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
 
     /**
      * Example of good provider metadata. Endpoints are localhost to support the 
@@ -262,9 +273,12 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         addBeanDefinition(builderContext, "shibboleth.ReplayCache",BeanDefinitionBuilder.
                 genericBeanDefinition(org.opensaml.storage.ReplayCache.class).getBeanDefinition());
         
+        addBeanDefinition(builderContext, "shibboleth.StorageService",BeanDefinitionBuilder.
+                genericBeanDefinition(org.opensaml.storage.impl.MemoryStorageService.class).getBeanDefinition());
+        
         
         try {
-            // Create a HttpClient which turns off hostname verification and trusts all certificates
+            // Create a HttpClient which turns off hostname verification and trusts all certificates (for TESTS!)
             addBeanSingleton(builderContext, "shibboleth.InternalHttpClient", 
                         HttpClients.custom().setSSLContext(new SSLContextBuilder()
                                 .loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
@@ -276,11 +290,13 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
   
         loadBeanDefinitionsFromXmlFile(builderContext, 
                 new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"),
-                null);
+                Map.of("idp.authn.oidc.rp.client.clientId", CLIENT_ID,
+                        "idp.authn.oidc.rp.client.clientSecret",CLIENT_SECRET));
         
         loadBeanDefinitionsFromXmlFile(builderContext, 
                 new ClassPathResource("conf/test-relyingparty-resolver-service.xml"), 
-                Map.of("idp.authn.oidc.rp.client.clientId", CLIENT_ID));
+                Map.of("idp.authn.oidc.rp.client.clientId", CLIENT_ID,
+                        "idp.authn.oidc.rp.client.clientSecret",CLIENT_SECRET));
         
         loadBeanDefinitionsFromXmlFile(builderContext, 
                 new ClassPathResource("conf/additional-system-beans.xml"), null);
@@ -294,7 +310,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
     
     /**
      * Create an OAuth access token with a runtime constructed id_token. This allows the
-     * expiry to be current.
+     * expiry to be current. The token is signed with the client_secret using HS256.
      * 
      * TODO the JWT is signed with a local MAC and is not consistent with the OP metadata. Might need to change this
      * 
@@ -317,7 +333,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(ID_TOKEN_HMAC_SECRET));
+        signedJWT.sign(new MACSigner(CLIENT_SECRET));
         final String accessTokenSerialized = "{\n"
         + "  \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
         + "  \"token_type\": \"Bearer\",\n"
@@ -328,6 +344,50 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         return accessTokenSerialized;
     }
     
+    /**
+     * Create an OAuth access token with a runtime constructed id_token. This allows the
+     * expiry to be current. The token is signed using HS256 and encrypted using the 'Direct Encryption' (dir)
+     * management mode i.e. no key wrapping. Both use the shared client_secret.
+     * 
+     * @return a serialized access token response.
+     * 
+     * @throws Exception on error.
+     */
+    private String createAccessTokenResponseJSONSignedAndEncrypted() throws Exception {
+        final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
+                .type(JOSEObjectType.JWT)
+                .build();
+        final var payload = new JWTClaimsSet.Builder()
+                .issuer(OP_ISSUER_ID)
+                .audience(List.of(CLIENT_ID,"demo_rp2"))
+                .subject("jdoe")
+                .claim("nonce", "abadnonce")
+                .claim("azp", CLIENT_ID)
+                .claim("name","jdoe")
+                .expirationTime(Date.from(Instant.now().plusSeconds(120)))
+                .build();
+        payload.getClaims().forEach((k,v) -> log.debug("{}:{}",k,v));
+        final var signedJWT = new SignedJWT(header,payload);
+        signedJWT.sign(new MACSigner(CLIENT_SECRET));
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .build(),
+                new Payload(signedJWT));
+        jweObject.encrypt(new DirectEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final String accessTokenSerialized = "{\n"
+        + "  \"access_token\": \"W0y5aDNAzEPNpSzu1cuMG904BZuQFZJUUwG5F3ct0zydZWy1ji\",\n"
+        + "  \"token_type\": \"Bearer\",\n"
+        + "  \"id_token\": \""+jwe.serialize()+"\",\n"
+        + "  \"scope\": \"openid\"\n"
+        + "}";
+        log.debug("Access token: \n {}",accessTokenSerialized);
+        return accessTokenSerialized;
+    }
+    
     /**
      * Create a signed UserInfo response JWT.
      * 
@@ -578,10 +638,36 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         final RelyingPartyContext partyContext = new RelyingPartyContext();
         final OIDCAuthorizationConfiguration partyConfig = new OIDCAuthorizationConfiguration();        
         partyContext.setProfileConfig(partyConfig);
-        partyConfig.setClientAuthenticationLookupStrategy(p ->
-            new ClientSecretBasic(new ClientID(CLIENT_ID), new Secret("secret")));
+        partyConfig.setClientAuthenticationMethod("client_secret_basic");
+        partyConfig.setClientId(CLIENT_ID);
+        partyConfig.setClientCredential(createCredentialFromSharedSecret(CLIENT_SECRET));
+        // Set a default security config for the profile config
+        final OIDCSecurityConfiguration secConfig = new OIDCSecurityConfiguration();
+        final BasicSignatureValidationConfiguration<SignedJWT> sigValidation = 
+                new BasicSignatureValidationConfiguration<>();
+        sigValidation.setSignatureTrustEngine(new ExplicitKeySignedJWTTrustEngine(
+                new CredentialResolver() {
+            
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+                jwkCredential.setAlgorithm(JWSAlgorithm.HS256);
+                jwkCredential.setKid("secret_key");                
+                jwkCredential.setSecretKey(new SecretKeySpec(
+                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));              
+                return jwkCredential;
+            }
+            
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        }));
+        
+        secConfig.setIdTokenJwtSignatureValidationConfig(sigValidation);
+        partyConfig.setSecurityConfiguration(secConfig);
                 
-        final RelyingPartyConfiguration rPartyConfig = new RelyingPartyConfiguration();
+        final RelyingPartyConfiguration rPartyConfig = new RelyingPartyConfiguration();        
         rPartyConfig.setResponderId("http://idp.example.com/");
         partyContext.setConfiguration(rPartyConfig);
         nestPrc.addSubcontext(partyContext);
@@ -691,7 +777,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         partyContext.setProfileConfig(partyConfig);
         
         partyConfig.setSecurityConfiguration(createSecurityConfigAndValidationParamsForHMAC(
-                ID_TOKEN_HMAC_SECRET.getBytes(), "HS256"));
+                CLIENT_SECRET.getBytes(), "HS256"));
         partyConfig.setClientAuthenticationLookupStrategy(p ->
             new ClientSecretBasic(new ClientID(CLIENT_ID), new Secret("secret")));
                 
@@ -737,7 +823,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
     }
     
     @Test 
-    public void testAuthnFlowFromAuthorizationCallback_UsingEncryptedJWTUserInfoResponse() 
+    public void testAuthnFlowFromAuthorizationCallback_Using_SignedAndEncrypted_JWTIDTokenAndUserInfoResponse() 
             throws Exception {
         
         setFlowPath(FLOW);
@@ -756,7 +842,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         // First is token exchange
         mockOPServer.enqueue(new MockResponse().setResponseCode(200)
                 .setHeader("content-type", "application/json")
-                .setBody(createAccessTokenResponseJSON()));
+                .setBody(createAccessTokenResponseJSONSignedAndEncrypted()));
         // Second is userInfo
         mockOPServer.enqueue(new MockResponse().setResponseCode(200)
                 .setHeader("content-type", "application/jwt")
@@ -778,8 +864,38 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
         final RelyingPartyContext partyContext = new RelyingPartyContext();
         final OIDCAuthorizationConfiguration partyConfig = new OIDCAuthorizationConfiguration();        
         partyContext.setProfileConfig(partyConfig);
-        partyConfig.setClientAuthenticationLookupStrategy(p ->
-            new ClientSecretBasic(new ClientID(CLIENT_ID), new Secret("secret")));
+        partyConfig.setClientAuthenticationMethod("client_secret_basic");
+        partyConfig.setClientId(CLIENT_ID);
+        partyConfig.setClientCredential(createCredentialFromSharedSecret(CLIENT_SECRET));
+        // Set a default security config for the profile config
+        final OIDCSecurityConfiguration secConfig = new OIDCSecurityConfiguration();
+        final BasicSignatureValidationConfiguration<SignedJWT> sigValidation = 
+                new BasicSignatureValidationConfiguration<>();
+        sigValidation.setSignatureTrustEngine(new ExplicitKeySignedJWTTrustEngine(
+                new CredentialResolver() {
+            
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+                jwkCredential.setAlgorithm(JWSAlgorithm.HS256);
+                jwkCredential.setKid("secret_key");                
+                jwkCredential.setSecretKey(new SecretKeySpec(
+                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));              
+                return jwkCredential;
+            }
+            
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        }));
+        
+        secConfig.setIdTokenJwtSignatureValidationConfig(sigValidation);
+        final var decryptConfig = new OIDCDecryptionConfiguration();
+        secConfig.setRequestObjectDecryptionConfiguration(null)
+        
+        partyConfig.setSecurityConfiguration(secConfig);
+        
                 
         final RelyingPartyConfiguration rPartyConfig = new RelyingPartyConfiguration();
         rPartyConfig.setResponderId("http://idp.example.com/");
@@ -910,6 +1026,21 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
        
     }
     
+    /**
+     * Create a basic {@link JWKCredential} from the given shared secret.
+     * 
+     * @param secret the secret to convert to a {@link JWKCredential}.
+     * 
+     * @return the credential
+     */
+    private JWKCredential createCredentialFromSharedSecret(final String secret) {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setSecretKey(new SecretKeySpec(JWSAssemblyUtils.getSecretBytes(secret), "NONE"));
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.UNSPECIFIED);
+        return jwkCredential;
+    }
+    
     
     /** 
      * Test the flow from the external authorization request to the end of the flow when an error
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 ecf2f28..ad811bc 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
@@ -8,6 +8,12 @@
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
 
     default-init-method="initialize" default-destroy-method="destroy">
+    
+    <!-- ***Some support beans from the internal rp configuration XML -->
+    
+     <!-- Parent bean for RelyingParty overrides based on activation by name(s). -->
+    <bean id="RelyingPartyByName" abstract="true" parent="RelyingParty"
+        class="net.shibboleth.idp.saml.relyingparty.impl.RelyingPartyConfigurationSupport" factory-method="byName" />
 
     <!-- removed, but I do not know what the default should be in this case
     p:defaultSecurityConfiguration-ref="%{idp.security.config:shibboleth.DefaultSecurityConfiguration}" -->
@@ -43,7 +49,7 @@
     <!-- Container for any overrides you want to add. -->
 
     <util:list id="shibboleth.RelyingPartyOverrides">
-    
+        
     </util:list>
    
     
@@ -51,7 +57,7 @@
     Map clients to appropriate client authentication - only supports client_secret_basic and client_secret_post
     -->
     
-    <util:map id="shibboleth.authn.oidc.rp.ClientIdToClientAuthenticationMap">
+   <!--  <util:map id="shibboleth.authn.oidc.rp.ClientIdToClientAuthenticationMap">
         <entry key="mytestclient">
             <bean parent="shibboleth.authn.oidc.rp.ClientAuthenticationDetails" c:clientSecret="mytestsecret"
                 c:tokenEndpointAuthMethod="client_secret_basic" />
@@ -60,7 +66,7 @@
             <bean parent="shibboleth.authn.oidc.rp.ClientAuthenticationDetails" c:clientSecret="mytestsecret"
                 c:tokenEndpointAuthMethod="client_secret_basic" />
         </entry>
-    </util:map>
+    </util:map> -->
 
 
 </beans>
\ No newline at end of file

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


More information about the commits mailing list