[java-idp-plugin-oidc-rp] branch main updated: JOIDCRP-14, JOIDCRP-13 - Client Authentication/Identifier Resolver

Phil Smart philip.smart at jisc.ac.uk
Mon Mar 28 13:57:09 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=21f3a4fcb303a15d3d8b47100b32e1095ed2f896

The following commit(s) were added to refs/heads/main by this push:
     new 21f3a4f  JOIDCRP-14, JOIDCRP-13 - Client Authentication/Identifier Resolver
21f3a4f is described below

commit 21f3a4fcb303a15d3d8b47100b32e1095ed2f896
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Mar 28 14:57:01 2022 +0100

    JOIDCRP-14, JOIDCRP-13 - Client Authentication/Identifier Resolver
    
     - Simplified the default strategies to use a simple Map over a further
    strategy which used a storage service.
    
    https://shibboleth.atlassian.net/browse/JOIDCRP-13
    https://shibboleth.atlassian.net/browse/JOIDCRP-14
---
 .../DefaultClientAuthenticationLookupStrategy.java | 171 +++++++++---
 .../DefaultClientIdentifierLookupStrategy.java     |  49 +++-
 ...ceBackedClientAuthenticationLookupStrategy.java | 291 ---------------------
 ...erviceBackedClientIdentifierLookupStrategy.java | 122 ---------
 .../idp/service/relying-party/postconfig.xml       |  36 +--
 ...aultClientAuthenticationLookupStrategyTest.java | 117 ++++++++-
 pom.xml                                            |   2 +-
 7 files changed, 287 insertions(+), 501 deletions(-)

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 189b5f7..cefdee5 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
@@ -19,76 +19,157 @@ package net.shibboleth.idp.plugin.authn.oidc.rp.config;
 
 import java.time.Duration;
 import java.time.Instant;
+import java.util.Collections;
 import java.util.Date;
+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 com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
 import com.nimbusds.oauth2.sdk.auth.Secret;
 
-import net.shibboleth.utilities.java.support.annotation.ParameterName;
+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.storage.ClientAuthenticationDetails;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
 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 authentication method either directly from the information supplied, 
  * or derived from a lookup strategy. 
  */
- at ThreadSafe
+ at ThreadSafeAfterInit
 public class DefaultClientAuthenticationLookupStrategy extends AbstractClientAuthenticationLookupStrategy {
     
     /** A fixed client_id to use.*/
-    @Nullable private final String clientId;
+    @Nullable private String clientId;
     
     /** A fixed client_secret to use over any injected strategy to locate one .*/
-    @Nullable private final String clientSecret;
+    @Nullable private char[] clientSecret;
     
     /** A fixed client authentication method to use.*/
-    @Nullable private final String clientAuthenticationMethod;
+    @Nullable private String clientAuthenticationMethod;
     
     /** A fixed client secret expiry in seconds since UNIX EPOCH to use.*/
-    @Nullable private final Duration clientSecretExpiresAt;
+    @Nullable private Duration clientSecretExpiresAt;
     
-    /** The strategy used to locate the client authentication method if a fixed one is not already supplied.*/
-    @Nullable private final Function<ProfileRequestContext, ClientAuthentication> clientAuthenticationLookupStrategy;
+    /** Map of client_id to client authentication details used to construct a {@link ClientAuthentication}.*/
+    @Nullable @NotLive private Map<String, ClientAuthenticationDetails> clientIdToClientAuthenticationMap;
+    
+    /** The strategy used to lookup or create the {@link OAuth2ClientContext}.*/
+    @Nonnull private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
     
 
     /**
-     * 
      * Constructor.
-     *
-     * @param id the client_id
-     * @param secret the client_secret
-     * @param authenticationMethod the client authentication method
-     * @param secretExpiresAt when the client secret expires, or 0 for no expiry
-     * @param strategy the strategy to lookup the client authentication 
-     * @throws ComponentInitializationException
      */
-    public DefaultClientAuthenticationLookupStrategy(
-            @ParameterName(name="clientId") @Nullable final String id,
-            @ParameterName(name="clientSecret") @Nullable final String secret,
-            @ParameterName(name="clientAuthenticationMethod") @Nullable final String authenticationMethod,
-            @ParameterName(name="clientSecretExpiresAt") @Nullable final Duration secretExpiresAt,
-            @ParameterName(name="clientIdLookupStrategy") 
-                @Nullable final Function<ProfileRequestContext, ClientAuthentication> strategy) 
-                    throws ComponentInitializationException {
+    public DefaultClientAuthenticationLookupStrategy() {        
+        oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class).compose(
+                new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
+                        new OutboundMessageContextLookup()));        
+    }
+    
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
         
-     
-        if (strategy == null && secret == null && authenticationMethod == null && secretExpiresAt == null) {
+        if (clientIdToClientAuthenticationMap == null && clientSecret == null && 
+                clientAuthenticationMethod == null && clientSecretExpiresAt == null) {
             
             throw new ComponentInitializationException("Must supply a client_secret, client_authentication_method,"
-                    + " and client_secret_expires_at if a client authentication lookup strategy is not supplied");
+                    + " and client_secret_expires_at if a client authentication map is not supplied");
         }
+
+    }
+    
+    /**
+     * Set the client_id. 
+     * 
+     * @param id the client_id
+     */
+    public void setClientId(@Nullable final String id) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
         clientId = StringSupport.trimOrNull(id);
-        clientSecret = StringSupport.trimOrNull(secret);
-        clientAuthenticationMethod = StringSupport.trimOrNull(authenticationMethod);
-        clientSecretExpiresAt = secretExpiresAt;
-        clientAuthenticationLookupStrategy = strategy;
+    }
+    
+    /**
+     * Set the client authentication method.
+     * 
+     * @param authMethod the client authentication method
+     */
+    public void setClientAuthenticationMethod(@Nullable final String authMethod) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        clientAuthenticationMethod = StringSupport.trimOrNull(authMethod);
+    }
+    
+    /**
+     * Set the client_secret. 
+     * 
+     * @param secret the client_secret
+     */
+    public void setClientSecret(@Nullable final char[] secret) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        clientSecret = secret;
+    }
+    
+    /**
+     * Set when the client_secret expires. A duration of 0 means the secret does not expire. 
+     * 
+     * @param expiresAt when the client secret expires, or 0 for no expiry.
+     */
+    public void setClientSecretExpiresAt(@Nullable final Duration expiresAt) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        clientSecretExpiresAt = expiresAt;
+    }
+    
+    /**
+     * Set the client_id to client authentication details map.
+     * 
+     * @param map the map of client_id to client authentication details
+     */
+    public void setClientIdToClientAuthenticationMap(
+            @Nullable final Map<String, ClientAuthenticationDetails> map) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        if (map == null) {
+            clientIdToClientAuthenticationMap = Collections.emptyMap();
+        } else {
+            clientIdToClientAuthenticationMap = 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");
     }
 
     @Override
@@ -99,13 +180,33 @@ public class DefaultClientAuthenticationLookupStrategy extends AbstractClientAut
                  && clientId != null) {
             if (clientSecretExpiresAt.toSeconds() == 0) {
                 // No expiry if 0, so do not set. 
-                return constructClientAuthentication(clientId, clientAuthenticationMethod, new Secret(clientSecret));
+                return constructClientAuthentication(clientId, clientAuthenticationMethod, 
+                        new Secret(new String(clientSecret)));
                 
             }            
-            return constructClientAuthentication(clientId, clientAuthenticationMethod, new Secret(clientSecret, 
+            return constructClientAuthentication(clientId, clientAuthenticationMethod, 
+                    new Secret(new String(clientSecret), 
                     Date.from(Instant.ofEpochSecond(clientSecretExpiresAt.toSeconds()))));
         }
-        return clientAuthenticationLookupStrategy.apply(profileRequestContext);
+        
+        // Else pull it from the map
+        final OAuth2ClientContext clientCtx = oauth2ClientContextLookupStrategy.apply(profileRequestContext);
+        if (clientCtx == null || StringSupport.trimOrNull(clientCtx.getClientId()) == null) {
+            return null;
+        }
+        final ClientAuthenticationDetails details = 
+                clientIdToClientAuthenticationMap.get(clientCtx.getClientId());
+        
+        if (details.getClientSecretExpiresAt() == 0) {
+            return constructClientAuthentication(
+                    clientCtx.getClientId(), details.getTokenEndpointAuthMethod(), 
+                    new Secret(new String(details.getClientSecret())));
+        } else {
+            final Instant secretExpiration = Instant.ofEpochSecond(details.getClientSecretExpiresAt());
+            return constructClientAuthentication(
+                    clientCtx.getClientId(), details.getTokenEndpointAuthMethod(), 
+                    new Secret(new String(details.getClientSecret()), Date.from(secretExpiration)));
+        }
     }
 
 }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientIdentifierLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientIdentifierLookupStrategy.java
index 784e674..34e513b 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientIdentifierLookupStrategy.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientIdentifierLookupStrategy.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.idp.plugin.authn.oidc.rp.config;
 
+import java.util.Collections;
+import java.util.Map;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -25,8 +27,12 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
+import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /**
@@ -39,29 +45,41 @@ public class DefaultClientIdentifierLookupStrategy implements Function<ProfileRe
     /** A fixed client_id to use over any injected strategy to locate one.*/
     @Nullable private final String clientId;
     
-    /** The strategy used to locate the client_id if a fixed one is not already supplied.*/
-    @Nullable private final Function<ProfileRequestContext, String> clientIdLookupStrategy;
+    /** Map of issuer to client_id. Can be {@literal null} if a fixed client_id is used.*/
+    @Nullable @NotLive private final Map<String, String> issuerToClientIdMap;
+    
+    /** Lookup strategy to locate the provider metadata to use.*/
+    @NonnullAfterInit 
+    private final Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
     
     /**
      * 
      * Constructor.
      *
      * @param id a client_id that takes precedence over one derived from the lookup strategy.
-     * @param strategy the strategy used to derive a client_id for the input profile request context.
+     * @param map the map used to derive a client_id for the input profile request context.
+     * @param strategy the strategy used to locate the provider metadata to find the issuer id. 
      * 
      * @throws ComponentInitializationException if both id and strategy are null, one is required.
      */
     public DefaultClientIdentifierLookupStrategy(@ParameterName(name="clientId") @Nullable final String id, 
-            @ParameterName(name="clientIdLookupStrategy") 
-                @Nullable final Function<ProfileRequestContext, String> strategy) 
+            @ParameterName(name="issuerToClientIdMap") @Nullable final Map<String, String> map,
+                @Nonnull @ParameterName(name="providerMetadataLookupStrategy") 
+                final Function<ProfileRequestContext, OIDCProviderMetadataContext> strategy) 
                     throws ComponentInitializationException {
      
-        if (id == null && strategy == null) {
-            throw new ComponentInitializationException("Must supply either a fixed client_id value or a "
-                    + "client_id lookup strategy");
+        if (id == null && map == null) {
+            throw new ComponentInitializationException("Must supply either a fixed client_id value or an "
+                    + "issuer to client_id map");
+        }
+        if (map != null) {
+            issuerToClientIdMap = Collections.unmodifiableMap(map);
+        } else {
+            issuerToClientIdMap = Collections.emptyMap();
         }
         clientId = StringSupport.trimOrNull(id);
-        clientIdLookupStrategy = strategy;
+        providerMetadataLookupStrategy = 
+                Constraint.isNotNull(strategy, "The provider metadata lookup strategy can not be null");
     }
 
     @Override
@@ -70,8 +88,19 @@ public class DefaultClientIdentifierLookupStrategy implements Function<ProfileRe
         // Use supplied client_id first
         if (clientId != null) {
             return clientId;
+        } else {
+            final OIDCProviderMetadataContext providerMetadataContext = 
+                    providerMetadataLookupStrategy.apply(profileRequestContext);
+            if (providerMetadataContext == null || providerMetadataContext.getProviderInformation() == null) {
+                return null;
+            }
+            
+            if (issuerToClientIdMap != null) {
+                //Should not be if we get here. 
+                return issuerToClientIdMap.get(providerMetadataContext.getProviderInformation().getIssuer().getValue());
+            }
         }
-        return clientIdLookupStrategy.apply(profileRequestContext);
+        return null;
     }
 
 }
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientAuthenticationLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientAuthenticationLookupStrategy.java
deleted file mode 100644
index eaa81d2..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientAuthenticationLookupStrategy.java
+++ /dev/null
@@ -1,291 +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.config;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.time.Instant;
-import java.util.Date;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import javax.json.Json;
-import javax.json.JsonException;
-import javax.json.JsonObject;
-import javax.json.JsonReader;
-import javax.json.JsonStructure;
-import javax.json.stream.JsonGenerator;
-
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
-import org.opensaml.storage.StorageRecord;
-import org.opensaml.storage.StorageSerializer;
-import org.opensaml.storage.StorageService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
-import com.nimbusds.oauth2.sdk.auth.Secret;
-
-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.NonnullAfterInit;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-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;
-
-/**
- * Default strategy for locating a configured client authentication method appropriate for the client_id
- * stashed in the {@link OAuth2ClientContext}.
- */
-public class StorageServiceBackedClientAuthenticationLookupStrategy 
-                            extends AbstractClientAuthenticationLookupStrategy  {
-    
-    /** The context name in the {@link StorageService}. */
-    @Nonnull @NotEmpty public static final String CONTEXT_NAME = "oauth2ClientAuthentication";
-    
-    /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(StorageServiceBackedClientAuthenticationLookupStrategy.class);
-    
-    /** The strategy used to lookup or create the {@link OAuth2ClientContext}.*/
-    @NonnullAfterInit 
-    private Function<ProfileRequestContext, OAuth2ClientContext> oauth2ClientContextLookupStrategy;
-    
-    /** The {@link StorageService} used to store a client identifier for a given Issuer. */
-    @NonnullAfterInit private StorageService storageService;
-    
-    /** 
-     * A storage service serializer for serializing and deserializing ClientAuthenticationRecords out of 
-     * storage records.
-     */
-    @Nonnull private StorageSerializer<ClientAuthenticationRecord> storageSerializer;
-    
-    /** Constructor. */
-    public StorageServiceBackedClientAuthenticationLookupStrategy() {
-        oauth2ClientContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientContext.class).compose(
-                new ChildContextLookup<>(OIDCPeerEntityContext.class).compose(
-                        new OutboundMessageContextLookup()));
-        
-        storageSerializer = new ClientAuthenticationStorageRecordSerializer();
-    }
-    
-    @Override
-    protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        
-        if (oauth2ClientContextLookupStrategy == null) {
-            throw new ComponentInitializationException("OAuth2ClientContextLookupStrategy cannot be null");
-        }
-        if (storageService == null) {
-            throw new ComponentInitializationException("StorageService cannot be null");
-        }
-    }
-    
-    /**
-     * Set the storage serializer to use with the storage service. 
-     * 
-     * @param serializer the storage serializer
-     */
-    public void setStorageSerializer(final StorageSerializer<ClientAuthenticationRecord> serializer) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-        
-        storageSerializer = Constraint.isNotNull(serializer, "Storage serializer can not be null");
-    }
-    
-    /**
-     * 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 {@link StorageService} back-end to use.
-     * 
-     * @param storage the back-end to use
-     */
-    public void setStorageService(@Nonnull final StorageService storage) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-
-        storageService = Constraint.isNotNull(storage, "StorageService cannot be null");
-    }
-
-    @Override
-    @Nullable public ClientAuthentication apply(@Nonnull final ProfileRequestContext profileRequestContext) {
-        final OAuth2ClientContext clientCtx = oauth2ClientContextLookupStrategy.apply(profileRequestContext);
-        if (clientCtx == null || StringSupport.trimOrNull(clientCtx.getClientId()) == null) {
-            return null;
-        }
-        try {
-            final StorageRecord<ClientAuthenticationRecord> record = 
-                    storageService.read(CONTEXT_NAME, clientCtx.getClientId());
-            if (record != null) {  
-                final ClientAuthenticationRecord clientAuthRecord = 
-                        record.getValue(storageSerializer, CONTEXT_NAME, clientCtx.getClientId());
-                return constructClientAuthentication(clientCtx.getClientId(),
-                        clientAuthRecord.getTokenEndpointAuthMethod(),
-                        clientAuthRecord.getClientSecret());
-            }
-        } catch (final IOException e) {
-            log.debug("{}: Error retrieving client_authentication record from the storage service", getId(), e);
-            return null;
-        }
-        return null;
-    }
-    
-    
-    
-    /** A Storage service serializer for converting between ClientAuthenticationRecords and JSON.*/
-    private static class ClientAuthenticationStorageRecordSerializer 
-                                    implements StorageSerializer<ClientAuthenticationRecord> {
-
-        /** Class logger. */
-        private final Logger log = LoggerFactory.getLogger(ClientAuthenticationStorageRecordSerializer.class);
-
-        @Override
-        public boolean isInitialized() {
-            // Is initialized once created
-            return true;
-        }
-
-        @Override
-        public void initialize() throws ComponentInitializationException {
-            //no-op here, does not need to be called.            
-        }
-
-        @Override
-        public String serialize(final ClientAuthenticationRecord instance) throws IOException {
-            
-            final StringWriter sink = new StringWriter(128);
-            
-            try (final JsonGenerator gen = Json.createGenerator(sink)) {  
-                
-                final String secretExpiryTimeSinceEpochUTC = Long.toString( 
-                        instance.getClientSecret().getExpirationDate().toInstant().getEpochSecond());
-                gen.writeStartObject()
-                    .write("token_endpoint_auth_method", instance.getTokenEndpointAuthMethod())
-                    .write("client_secret", instance.getClientSecret().getValue())
-                    .write("client_secret_expires_at", secretExpiryTimeSinceEpochUTC);
-                                
-                gen.writeEnd().close();
-                
-                return sink.toString();
-            } catch (final JsonException e) {
-                log.error("Exception while serializing ClientAuthenticationRecord: {}", e.getMessage());
-                throw new IOException("Exception while serializing ClientAuthenticationRecord", e);
-            }
-        }
-
-        @Override
-        public ClientAuthenticationRecord deserialize(
-                final long version, final String context, final String key, final String value,
-                final Long expiration) throws IOException {
-            
-            try (final JsonReader reader = Json.createReader(new StringReader(value))) {
-                
-                final JsonStructure st = reader.read();
-                if (!(st instanceof JsonObject)) {
-                    throw new IOException("Found invalid data structure while parsing ClientAuthenticationRecord");
-                }
-                final JsonObject obj = (JsonObject) st;
-                
-                final String tokenEndpointAuthMethod = obj.getString("token_endpoint_auth_method");
-                final String secret = obj.getString("client_secret");
-                final long expiryInSeconds = obj.getJsonNumber("client_secret_expires_at").longValueExact();
-                
-                if (expiryInSeconds == 0) {
-                    // Then no expiry
-                    return new ClientAuthenticationRecord(tokenEndpointAuthMethod, new Secret(secret));
-                } else {
-                    final Instant secretExpiration = Instant.ofEpochSecond(expiryInSeconds);
-                    return new ClientAuthenticationRecord(
-                            tokenEndpointAuthMethod, new Secret(secret, Date.from(secretExpiration)));
-                }
-                
-
-                
-                
-            } catch (final NullPointerException | ClassCastException | ArithmeticException | JsonException e) {
-                log.error("Exception while parsing ClientAuthenticationRecord: {}", e.getMessage());
-                throw new IOException("Found invalid data structure while parsing ClientAuthenticationRecord", e);
-            }
-        }
-        
-    }
-    
-    /**
-     * A client authentication record that is serialized in and out of a storage service.
-     */
-    @Immutable
-    private static class ClientAuthenticationRecord {
-        
-        /** The client authentication method for the token endpoint.*/
-        @Nonnull private final String tokenEndpointAuthMethod;
-        
-        /** the client secret.*/
-        @Nonnull private final Secret clientSecret;
-
-        /**
-         * Constructor.
-         *
-         * @param authMethod the client authentication method
-         * @param secret the client secret
-         */
-        public ClientAuthenticationRecord(@Nonnull final String authMethod, @Nonnull final Secret secret) {
-            tokenEndpointAuthMethod = 
-                    Constraint.isNotEmpty(authMethod, "Authentication method type can not be null or empty");
-            clientSecret = Constraint.isNotNull(secret, "Client Secrete can not be null");
-        }
-
-        /**
-         * Get the token_endpoint_auth_method.
-         * 
-         * @return Returns the tokenEndpointAuthMethod.
-         */
-        public final String getTokenEndpointAuthMethod() {
-            return tokenEndpointAuthMethod;
-        }
-
-        /**
-         * Get the client_sercret. 
-         * 
-         * @return Returns the clientSecret.
-         */
-        public final Secret getClientSecret() {
-            return clientSecret;
-        }
-        
-    }
-
-}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientIdentifierLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientIdentifierLookupStrategy.java
deleted file mode 100644
index 8270037..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/StorageServiceBackedClientIdentifierLookupStrategy.java
+++ /dev/null
@@ -1,122 +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.config;
-
-import java.io.IOException;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.storage.StorageRecord;
-import org.opensaml.storage.StorageService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-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;
-
-/**
- * Default strategy for locating a client_id in the storage service based on the issuer_id found 
- * in the provider metadata.
- */
-public class StorageServiceBackedClientIdentifierLookupStrategy extends AbstractIdentifiableInitializableComponent
-                            implements Function<ProfileRequestContext, String> {
-    
-    /** The context name in the {@link StorageService}. */
-    @Nonnull @NotEmpty public static final String CONTEXT_NAME = "oauth2ClientIdentifier";
-    
-    /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(StorageServiceBackedClientIdentifierLookupStrategy.class);
-    
-    /** Lookup strategy to locate the provider metadata to use.*/
-    @NonnullAfterInit 
-    private Function<ProfileRequestContext, OIDCProviderMetadataContext> providerMetadataLookupStrategy;
-    
-    /** The {@link StorageService} used to store a client_id for a given issuer_id. */
-    @NonnullAfterInit private StorageService storageService;
-    
-    
-    /**
-     * Set the lookup strategy to locate the OpenID providers metadata.
-     * 
-     * @param strategy the strategy.
-     */
-    public void setProviderMetadataLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCProviderMetadataContext> strategy) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        
-        providerMetadataLookupStrategy = 
-                Constraint.isNotNull(strategy,"Provider metadata lookup strategy can not be null");
-    }
-    
-    @Override
-    public void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        if (storageService == null) {
-            throw new ComponentInitializationException(getId() + ": StorageService cannot be null");
-        }
-        if (providerMetadataLookupStrategy == null) {
-            throw new ComponentInitializationException(
-                    getId() + ": OIDC Provider metadata lookup strategy cannot be null");
-        }
-    }   
- 
-    /**
-     * Set the {@link StorageService} back-end to use.
-     * 
-     * @param storage the back-end to use
-     */
-    public void setStorageService(@Nonnull final StorageService storage) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
-
-        storageService = Constraint.isNotNull(storage, "StorageService cannot be null");
-    }
-
-    @Override
-    @Nullable public String apply(@Nonnull final ProfileRequestContext profileRequestContext) {
-        
-        final OIDCProviderMetadataContext providerMetadataContext = 
-                providerMetadataLookupStrategy.apply(profileRequestContext);
-        if (providerMetadataContext == null || providerMetadataContext.getProviderInformation() == null) {
-            log.warn("{} No provider metadata found for peer,  nothing to do", getId());
-            return null;
-        }
-        
-        try {
-            final StorageRecord<?> record = 
-                    storageService.read(CONTEXT_NAME, 
-                            providerMetadataContext.getProviderInformation().getIssuer().getValue());
-            if (record != null) {
-                return record.getValue();
-            }
-        } catch (final IOException e) {
-            log.warn(getId() + "{}: StorageService read failed, could not acquire client_id for issuer {}", getId(),
-                    providerMetadataContext.getProviderInformation().getIssuer(), e);
-        }
-        return null;
-    }
-
-}
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 573f224..5feae96 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
@@ -32,43 +32,21 @@
         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')}" />
-
     
     <bean id="shibboleth.authn.oidc.rp.DefaultClientAuthenticationLookStrategy"
         class="net.shibboleth.idp.plugin.authn.oidc.rp.config.DefaultClientAuthenticationLookupStrategy"
-        c:clientId="%{idp.authn.oidc.rp.client.clientId:#{null}}"
-        c:clientSecret="%{idp.authn.oidc.rp.client.clientSecret:#{null}}"
-        c:clientAuthenticationMethod="%{idp.authn.oidc.rp.client.clientAuthenticationMethod:client_secret_basic}"
-        c:clientSecretExpiresAt="%{idp.authn.oidc.rp.client.clientSecretExpiresAt:PT0S}"
-        c:clientIdLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.EmbeddedClientAuthenticationLookupStrategy') ?: getObject('shibboleth.authn.oidc.rp.StorageServiceBackedClientAuthenticationLookStrategy')}"/>
-    
+        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:clientIdLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.EmbeddedClientIdentifierLookupStrategy') ?: getObject('shibboleth.authn.oidc.rp.StorageServiceBackedClientIdentifierLookupStrategy')}"/>
-    
-    <bean id="shibboleth.authn.oidc.rp.StorageServiceBackedClientIdentifierLookupStrategy" lazy-init="true"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.StorageServiceBackedClientIdentifierLookupStrategy"
-        p:providerMetadataLookupStrategy-ref="shibboleth.ChildLookup.OIDCProviderMetadataContextFromOutbound"
-        p:storageService="#{getObject('shibboleth.authn.oidc.rp.StorageService') ?: getObject('shibboleth.authn.oidc.rp.DefaultMapBackedClientIdStorageService')}" />
+        c:issuerToClientIdMap="#{getObject('shibboleth.authn.oidc.rp.IssuerToClientIdMap')}"
+        c:providerMetadataLookupStrategy-ref="shibboleth.ChildLookup.OIDCProviderMetadataContextFromOutbound"/>
     
-    <bean id="shibboleth.authn.oidc.rp.DefaultMapBackedClientIdStorageService" scope="prototype"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.MapBackedMemoryStorageServiceFactoryBean"
-        c:context="#{T(net.shibboleth.idp.plugin.authn.oidc.rp.config.StorageServiceBackedClientIdentifierLookupStrategy).CONTEXT_NAME}"
-        c:map="#{getObject('shibboleth.authn.oidc.rp.IssuerToClientIdMap')}"
-        c:id="DefaultIssuerToClientIDMapStorageService" />
-    
-    <bean id="shibboleth.authn.oidc.rp.StorageServiceBackedClientAuthenticationLookStrategy" lazy-init="true"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.StorageServiceBackedClientAuthenticationLookupStrategy"
-        p:storageService="#{getObject('shibboleth.authn.oidc.rp.ClientAuthenticationStorageService') ?: getObject('shibboleth.authn.oidc.rp.DefaultMapBackedClientAuthenticationStorageService')}" />
-
-    <bean id="shibboleth.authn.oidc.rp.DefaultMapBackedClientAuthenticationStorageService" lazy-init="true"
-        class="net.shibboleth.idp.plugin.authn.oidc.rp.config.MapBackedMemoryStorageServiceFactoryBean"
-        c:context="#{T(net.shibboleth.idp.plugin.authn.oidc.rp.config.StorageServiceBackedClientAuthenticationLookupStrategy).CONTEXT_NAME}"
-        c:map="#{getObject('shibboleth.authn.oidc.rp.ClientIdToClientAuthenticationMap')}"
-        c:id="DefaultClientIDToClientAuthenticationMapStorageService" />
-
     <!-- 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"
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategyTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategyTest.java
index 60d257e..50359d5 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategyTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/DefaultClientAuthenticationLookupStrategyTest.java
@@ -23,16 +23,20 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import java.time.Duration;
+import java.time.Instant;
+import java.util.Map;
 
+import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.testng.annotations.Test;
 
 import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
 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.OAuth2ClientContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.storage.ClientAuthenticationDetails;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 
 /** Tests for the DefaultClientAuthenticationLookupStrategy.*/
@@ -43,8 +47,11 @@ public class DefaultClientAuthenticationLookupStrategyTest {
     
     @Test
     public void testBuildFromProperties() throws ComponentInitializationException {
-        strategy = new DefaultClientAuthenticationLookupStrategy("client_id", "client_secret", "client_secret_basic", 
-                Duration.ofSeconds(0), s -> null);
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientId("client_id");
+        strategy.setClientSecret("client_secret".toCharArray());
+        strategy.setClientSecretExpiresAt(Duration.ofSeconds(0));
+        strategy.setClientAuthenticationMethod("client_secret_basic");
         strategy.setId("MockAuthenticationLookupStrategy");
         strategy.initialize();
         
@@ -55,10 +62,20 @@ public class DefaultClientAuthenticationLookupStrategyTest {
         assertFalse(((ClientSecretBasic)clientAuth).getClientSecret().expired());
     }
     
+    @Test(expectedExceptions = ComponentInitializationException.class)
+    public void testInitialisationFailed() throws ComponentInitializationException {
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setId("MockAuthenticationLookupStrategy");
+        strategy.initialize();
+    }
+    
     @Test
     public void testBuildFromProperties_SecretExpired() throws ComponentInitializationException {
-        strategy = new DefaultClientAuthenticationLookupStrategy("client_id", "client_secret", "client_secret_basic", 
-                Duration.ofSeconds(1), s -> null);
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientId("client_id");
+        strategy.setClientSecret("client_secret".toCharArray());
+        strategy.setClientSecretExpiresAt(Duration.ofSeconds(1));
+        strategy.setClientAuthenticationMethod("client_secret_basic");
         strategy.setId("MockAuthenticationLookupStrategy");
         strategy.initialize();
         
@@ -67,13 +84,22 @@ public class DefaultClientAuthenticationLookupStrategyTest {
     }
     
     @Test
-    public void testBuildFromStrategy() throws ComponentInitializationException {
-        strategy = new DefaultClientAuthenticationLookupStrategy(null, null, null, 
-                null, s -> new ClientSecretPost(new ClientID("client_id"), new Secret("client_secret")));
+    public void testBuildFromMap() throws ComponentInitializationException {
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientIdToClientAuthenticationMap(
+                Map.of("client_id", 
+                        new ClientAuthenticationDetails("client_secret".toCharArray(), 0, "client_secret_post")));
         strategy.setId("MockAuthenticationLookupStrategy");
         strategy.initialize();
         
-        final ClientAuthentication clientAuth = strategy.apply(new ProfileRequestContext());
+        final var prc = new ProfileRequestContext();
+        final var outBnd = new MessageContext();
+        final var clientContext = outBnd.getSubcontext(OIDCPeerEntityContext.class, true)
+                .getSubcontext(OAuth2ClientContext.class,true);
+        clientContext.setClientId("client_id");
+        prc.setOutboundMessageContext(outBnd);
+        
+        final ClientAuthentication clientAuth = strategy.apply(prc);
         assertEquals(clientAuth.getClientID().getValue(), "client_id");
         assertTrue(clientAuth instanceof ClientSecretPost);
         assertEquals(((ClientSecretPost)clientAuth).getClientSecret().getValue(), "client_secret");
@@ -82,16 +108,81 @@ public class DefaultClientAuthenticationLookupStrategyTest {
     
     @Test
     public void testBuildFromStrategy_PartialClientProperties() throws ComponentInitializationException {
-        strategy = new DefaultClientAuthenticationLookupStrategy("client_id", "client_secret", null, 
-                null, s -> new ClientSecretPost(new ClientID("client_id"), new Secret("client_secret")));
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientId("client_id_static");
+        strategy.setClientSecret("client_secret_static".toCharArray());
+        strategy.setClientSecretExpiresAt(null);
+        strategy.setClientAuthenticationMethod(null);
+        strategy.setClientIdToClientAuthenticationMap(
+                Map.of("client_id", 
+                        new ClientAuthenticationDetails("client_secret".toCharArray(), 0, "client_secret_post")));
         strategy.setId("MockAuthenticationLookupStrategy");
         strategy.initialize();
         
-        final ClientAuthentication clientAuth = strategy.apply(new ProfileRequestContext());
+        final var prc = new ProfileRequestContext();
+        final var outBnd = new MessageContext();
+        final var clientContext = outBnd.getSubcontext(OIDCPeerEntityContext.class, true)
+                .getSubcontext(OAuth2ClientContext.class,true);
+        clientContext.setClientId("client_id");
+        prc.setOutboundMessageContext(outBnd);
+        
+        final ClientAuthentication clientAuth = strategy.apply(prc);
         assertEquals(clientAuth.getClientID().getValue(), "client_id");
         assertTrue(clientAuth instanceof ClientSecretPost);
         assertEquals(((ClientSecretPost)clientAuth).getClientSecret().getValue(), "client_secret");
         assertFalse(((ClientSecretPost)clientAuth).getClientSecret().expired());      
     }
+    
+    @Test
+    public void testBuildFromStrategy_PartialClientProperties_ExpiredSecret() throws ComponentInitializationException {
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientId("client_id_static");
+        strategy.setClientSecret("client_secret_static".toCharArray());
+        strategy.setClientSecretExpiresAt(null);
+        strategy.setClientAuthenticationMethod(null);
+        strategy.setClientIdToClientAuthenticationMap(
+                Map.of("client_id", 
+                        new ClientAuthenticationDetails("client_secret".toCharArray(), 1, "client_secret_post")));
+        strategy.setId("MockAuthenticationLookupStrategy");
+        strategy.initialize();
+        
+        final var prc = new ProfileRequestContext();
+        final var outBnd = new MessageContext();
+        final var clientContext = outBnd.getSubcontext(OIDCPeerEntityContext.class, true)
+                .getSubcontext(OAuth2ClientContext.class,true);
+        clientContext.setClientId("client_id");
+        prc.setOutboundMessageContext(outBnd);
+        final ClientAuthentication clientAuth = strategy.apply(prc);
+        assertNull(clientAuth);    
+    }
+    
+    @Test
+    public void testBuildFromStrategy_PartialClientProperties_SecretNearlyExpired() 
+            throws ComponentInitializationException {
+        strategy = new DefaultClientAuthenticationLookupStrategy();
+        strategy.setClientId("client_id_static");
+        strategy.setClientSecret("client_secret_static".toCharArray());
+        strategy.setClientSecretExpiresAt(null);
+        strategy.setClientAuthenticationMethod(null);
+        strategy.setClientIdToClientAuthenticationMap(
+                Map.of("client_id", 
+                        new ClientAuthenticationDetails("client_secret".toCharArray(), 
+                                Instant.now().plus(Duration.ofSeconds(10)).getEpochSecond(), "client_secret_post")));
+        strategy.setId("MockAuthenticationLookupStrategy");
+        strategy.initialize();
+        
+        final var prc = new ProfileRequestContext();
+        final var outBnd = new MessageContext();
+        final var clientContext = outBnd.getSubcontext(OIDCPeerEntityContext.class, true)
+                .getSubcontext(OAuth2ClientContext.class,true);
+        clientContext.setClientId("client_id");
+        prc.setOutboundMessageContext(outBnd);
+        
+        final ClientAuthentication clientAuth = strategy.apply(prc);
+        assertEquals(clientAuth.getClientID().getValue(), "client_id");
+        assertTrue(clientAuth instanceof ClientSecretPost);
+        assertEquals(((ClientSecretPost)clientAuth).getClientSecret().getValue(), "client_secret");
+        assertFalse(((ClientSecretPost)clientAuth).getClientSecret().expired());        
+    }
 
 }
diff --git a/pom.xml b/pom.xml
index 05904f9..a0bde1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,7 +19,7 @@
         <idp.version>4.2.0-SNAPSHOT</idp.version>
         <opensaml.groupId>org.opensaml</opensaml.groupId>
         <opensaml.version>4.2.0-SNAPSHOT</opensaml.version>
-        <oidc.common.version>1.2.0-SNAPSHOT</oidc.common.version>
+        <oidc.common.version>2.0.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