[java-plugin-shibd-oidc] branch main updated: JSHIBDOIDC-11 - Fix provider metadata handling

Codeberg noreply at shibboleth.net
Fri Feb 6 11:52:41 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-plugin-shibd-oidc.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-oidc/commit/096642eb6aecd0ae2109c2636bfcacc19e02add8

The following commit(s) were added to refs/heads/main by this push:
     new 096642e  JSHIBDOIDC-11 - Fix provider metadata handling
096642e is described below

commit 096642eb6aecd0ae2109c2636bfcacc19e02add8
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Feb 6 11:52:31 2026 +0000

    JSHIBDOIDC-11 - Fix provider metadata handling
    
     - Based on the new work in
    https://shibboleth.atlassian.net/browse/JSHIBD-7 , added an OIDC
    specific protocol support service.
     - Added support for OpenID Provider metadata lookups using the
    configurable provider resolver.
     - Obtain the metadata resolver from the Application's Protocol Support
    Service.
    
    https://shibboleth.atlassian.net/browse/JSHIBDOIDC-11
---
 .../sp/oidc/BasicOIDCProtocolSupportService.java   | 61 ++++++++++++++++++++++
 .../sp/oidc/OIDCProtocolSupportService.java        | 40 ++++++++++++++
 .../java/net/shibboleth/sp/oidc/package-info.java  | 18 +++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     | 11 ++--
 .../idp/flows/sp/consumer/oidc/oidc-beans.xml      | 11 ----
 .../idp/flows/sp/initiator/oidc/oidc-beans.xml     | 11 ----
 .../shibboleth/idp/flows/sp/oidc-common-beans.xml  | 14 +++++
 .../net/shibboleth/sp/service/agent/postconfig.xml |  3 +-
 .../module/conf/oidc-metadata-providers-system.xml | 61 ++++++++++------------
 .../oidc/flows/OIDCSessionInitiatorFlowTest.java   | 60 +++++++++++++++++++++
 .../sp/oidc/flows/OIDCTokenConsumerFlowTest.java   | 25 ++++++++-
 .../idp/module/conf/sp/oidc-metadata-providers.xml | 34 ++++++++++++
 .../idp/module/conf/sp/oidc-test-agents.xml        | 12 ++---
 .../ApplicationMetadataResolverLookupFunction.java | 51 ++++++++----------
 .../sp/oidc/profile/impl/ExtractOIDCClaims.java    | 28 +++++++---
 15 files changed, 328 insertions(+), 112 deletions(-)

diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/BasicOIDCProtocolSupportService.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/BasicOIDCProtocolSupportService.java
new file mode 100644
index 0000000..c3cf21e
--- /dev/null
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/BasicOIDCProtocolSupportService.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.service.ReloadableService;
+import net.shibboleth.sp.BasicProtocolSupportService;
+
+/**
+ * A basic implementation of {@link OIDCProtocolSupportService}.
+ */
+public class BasicOIDCProtocolSupportService extends BasicProtocolSupportService implements OIDCProtocolSupportService {
+
+    /** Metadata source. */
+    @NonnullAfterInit private ReloadableService<ProviderMetadataResolver> metadataResolver;
+
+    /** [{@inheritDoc} */
+    @NonnullAfterInit
+    public ReloadableService<ProviderMetadataResolver> getMetadataResolver() {
+        return metadataResolver;
+    }
+
+    /**
+     * Sets the {@link ProviderMetadataResolver} to use.
+     * 
+     * @param service
+     *            metadata resolver service
+     */
+    public void setMetadataResolver(@Nonnull final ReloadableService<ProviderMetadataResolver> service) {
+        checkSetterPreconditions();
+
+        metadataResolver = Constraint.isNotNull(service, "ProviderMetadataResolver service cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+
+        if (metadataResolver == null) {
+            throw new ComponentInitializationException("ProviderMetadataResolver cannot be null");
+        }
+    }
+
+}
diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/OIDCProtocolSupportService.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/OIDCProtocolSupportService.java
new file mode 100644
index 0000000..fe178e5
--- /dev/null
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/OIDCProtocolSupportService.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.oidc;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.service.ReloadableService;
+import net.shibboleth.sp.ProtocolSupportService;
+
+/**
+ * OIDC subinterface of {@link ProtocolSupportService} to add any OIDC-specific features or services.
+ */
+public interface OIDCProtocolSupportService extends ProtocolSupportService {
+    
+    /** Key of the map entry for this subtype. */
+    @Nonnull @NotEmpty static String PROTOCOL_ID = "OIDC";
+    
+    /**
+     * Gets the default {@link ProviderMetadataResolver} service to use.
+     * 
+     * @return service to use
+     */
+    @NonnullAfterInit ReloadableService<ProviderMetadataResolver> getMetadataResolver();
+
+}
diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/package-info.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/package-info.java
new file mode 100644
index 0000000..a72d8e5
--- /dev/null
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Supporting APIs and classes for OIDC protocol support in the SP Hub.
+ */
+package net.shibboleth.sp.oidc;
\ No newline at end of file
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 6a74492..2b2cdb3 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -89,12 +89,6 @@
         </property>
     </bean>
 
-
-    <!-- OpenID Provider information resolver service beans. -->
-    <bean id="shibboleth.authn.oidc.rp.ProviderMetadataResolver"
-        class="net.shibboleth.oidc.metadata.impl.ReloadingProviderMetadataProvider"
-        c:resolverService-ref="shibboleth.ProviderMetadataResolverService" />
-
     <bean id="shibboleth.ProviderMetadataResolverService"
         class="net.shibboleth.shared.spring.service.ReloadableSpringService"
         p:serviceConfigurations-ref="ExtendedProviderMetadataResolverResources"
@@ -109,8 +103,9 @@
         </constructor-arg>
     </bean>
 
-    <!-- <util:list id="shibboleth.DefaultProviderMetadataResolverResources"> <value>conditional:%{idp.home}/conf/authn/oidc-metadata-providers.xml</value> 
-        </util:list> -->
+    <util:list id="shibboleth.DefaultProviderMetadataResolverResources"> 
+        <value>conditional:%{idp.home}/conf/sp/oidc-metadata-providers.xml</value> 
+    </util:list>
 
     <!-- Auto-append system config file to resource set. -->
     <bean id="ExtendedProviderMetadataResolverResources"
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/oidc/oidc-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/oidc/oidc-beans.xml
index e487de8..21bff5c 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/oidc/oidc-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/oidc/oidc-beans.xml
@@ -74,17 +74,6 @@
         class="net.shibboleth.sp.oidc.profile.impl.ValidateResponseState"
         p:nonceTokenLookupStrategy-ref="NonceFromStateLookup" />
         
-     <bean id="ProviderMetadataLookup" parent="WebFlowInboundMessageHandlerAdaptor">
-        <constructor-arg name="messageHandler"> <!-- TODO Copied over -->
-            <bean class="net.shibboleth.sp.oidc.metadata.impl.OIDCProviderMetadataLookupHandler"
-                scope="prototype">
-                <property name="ProviderMetadataResolverLookupStrategy">
-                    <bean class="net.shibboleth.sp.oidc.metadata.impl.ApplicationMetadataResolverLookupFunction" /> <!-- TODO Needs to be core-sp version -->
-                </property>
-            </bean>
-        </constructor-arg>
-    </bean>
-    
      <bean id="InitializeRelyingPartyContextFromOIDCPeer"
         class="net.shibboleth.sp.oidc.profile.impl.InitializeRelyingPartyContextFromOIDCPeer" scope="prototype" />
         
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
index a807a85..2b03136 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
@@ -28,17 +28,6 @@
         p:relyingPartyLookupStrategy-ref="shibboleth.RelyingPartyIdLookup.Simple">
     </bean>
     
-    <bean id="ProviderMetadataLookup" parent="WebFlowInboundMessageHandlerAdaptor">
-        <constructor-arg name="messageHandler"> <!-- TODO Copied over -->
-            <bean class="net.shibboleth.sp.oidc.metadata.impl.OIDCProviderMetadataLookupHandler"
-                scope="prototype">
-                <property name="ProviderMetadataResolverLookupStrategy">
-                    <bean class="net.shibboleth.sp.oidc.metadata.impl.ApplicationMetadataResolverLookupFunction" /> <!-- TODO Needs to be core-sp version -->
-                </property>
-            </bean>
-        </constructor-arg>
-    </bean>
-    
     <bean id="InitializeRelyingPartyContextFromOIDCPeer"
         class="net.shibboleth.sp.oidc.profile.impl.InitializeRelyingPartyContextFromOIDCPeer" scope="prototype" />
         
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/oidc-common-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/oidc-common-beans.xml
index e2992a7..e264dde 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/oidc-common-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/oidc-common-beans.xml
@@ -177,5 +177,19 @@
             <ref bean="shibboleth.MessageContextLookup.Inbound" />
         </constructor-arg>
     </bean>
+    
+    <!-- Common Actions -->
+    
+    <bean id="ProviderMetadataLookup" parent="WebFlowInboundMessageHandlerAdaptor" scope="prototype">
+        <constructor-arg name="messageHandler"> <!-- TODO move into common beans? -->
+            <bean class="net.shibboleth.sp.oidc.metadata.impl.OIDCProviderMetadataLookupHandler"
+                scope="prototype">
+                <property name="ProviderMetadataResolverLookupStrategy">
+                    <bean class="net.shibboleth.sp.oidc.profile.impl.ApplicationMetadataResolverLookupFunction" />
+                </property>
+            </bean>
+        </constructor-arg>
+    </bean>
+    
 
 </beans>
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
index a4dead3..607b60e 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
@@ -18,10 +18,11 @@
 <!--     <import resource="relying-party-mddriven.xml" /> -->
 
     <!-- Auto-wired protocol service support bean for use by parent plugin. -->
-    <bean class="net.shibboleth.sp.BasicProtocolSupportService"
+    <bean class="net.shibboleth.sp.oidc.BasicOIDCProtocolSupportService"
         p:id="OIDC"
         p:order="%{sp.oidc.relativeOrder:1}"
         p:sessionInitiators="oidc"
+        p:metadataResolver-ref="shibboleth.ProviderMetadataResolverService"
         p:tokenConsumers="#{{'oidc/code/query', 'oidc/code/post'}}">
         <property name="defaultProfileConfigurations">
             <list>
diff --git a/sp-oidc-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/oidc-metadata-providers-system.xml b/sp-oidc-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/oidc-metadata-providers-system.xml
index 5092369..c7eb218 100644
--- a/sp-oidc-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/oidc-metadata-providers-system.xml
+++ b/sp-oidc-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/oidc-metadata-providers-system.xml
@@ -9,81 +9,76 @@
 
     default-init-method="initialize" default-destroy-method="destroy" default-lazy-init="true">
 
-    <!-- Loaded by the postconfig.xml file as global beans -->
-    
-    <!-- TODO bean IDs are all wrong -->
-    <!-- TODO is this in the correct place in the tree -->
-
-    <bean id="shibboleth.authn.oidc.rp.ProviderMetadataProvider" lazy-init="false"
+    <bean id="shibboleth.sp.ProviderMetadataProvider" lazy-init="false"
         class="net.shibboleth.oidc.metadata.ProviderMetadataProviderContainer"
-        p:embeddedResolver-ref="shibboleth.authn.oidc.rp.ChainingProviderMetadataResolver">
+        p:embeddedResolver-ref="shibboleth.sp.ChainingProviderMetadataResolver">
     </bean>
 
-    <bean id="shibboleth.authn.oidc.rp.ChainingProviderMetadataResolver"
+    <bean id="shibboleth.sp.ChainingProviderMetadataResolver"
         class="net.shibboleth.oidc.metadata.impl.ChainingProviderMetadataResolver" p:id="InternalEmbeddedChainResolver"
-        p:resolvers="#{getObject('shibboleth.authn.oidc.rp.ProviderMetadataResolvers')}" />
+        p:resolvers="#{getObject('shibboleth.sp.ProviderMetadataResolvers')}" />
 
     <!-- abstract beans for the user space config to extend -->
-    <bean id="shibboleth.authn.oidc.rp.OIDCProviderMetadataResolver" abstract="true"
+    <bean id="shibboleth.sp.OIDCProviderMetadataResolver" abstract="true"
         class="net.shibboleth.oidc.metadata.impl.OIDCProviderMetadataResolver" />
 
-    <bean id="shibboleth.authn.oidc.rp.DefaultHTTPProviderConfigurationMetadataFetchingStrategy"
+    <bean id="shibboleth.sp.DefaultHTTPProviderConfigurationMetadataFetchingStrategy"
         class="net.shibboleth.oidc.metadata.impl.HTTPProviderConfigurationFetchingStrategy"        
-        c:client-ref="shibboleth.InternalHttpClient"
-        c:handler-ref="shibboleth.authn.oidc.rp.DefaultHTTProviderConfigurationMetadataResponseHandler" 
-        p:wellKnownLocationCompositionStrategy="#{getObject('shibboleth.authn.oidc.rp.WellKnownLocationCompositionStrategy')}"/>
+        c:client="#{getObject('%{sp.oidc.HttpClient:}') ?: getObject('shibboleth.InternalHttpClient')}"
+        c:handler-ref="shibboleth.sp.DefaultHTTProviderConfigurationMetadataResponseHandler" 
+        p:wellKnownLocationCompositionStrategy="#{getObject('shibboleth.sp.WellKnownLocationCompositionStrategy')}"/>
 
 
-    <bean id="shibboleth.authn.oidc.rp.DefaultHTTProviderConfigurationMetadataResponseHandler"
+    <bean id="shibboleth.sp.DefaultHTTProviderConfigurationMetadataResponseHandler"
         class="net.shibboleth.oidc.metadata.impl.HTTPProviderConfigurationFetchingStrategy.OIDCProviderMetadataResponseHandler" />
 
     <!-- Cache builder specifications -->
     <bean id="cacheFactory" class="net.shibboleth.oidc.metadata.cache.impl.MetadataCacheBuilder$Builder"/>
     
-    <bean id="shibboleth.authn.oidc.rp.CacheBuilder" factory-bean="cacheFactory" factory-method="build"
+    <bean id="shibboleth.sp.CacheBuilder" factory-bean="cacheFactory" factory-method="build"
         abstract="true"/>
     
     
     <bean class="net.shibboleth.oidc.metadata.cache.impl.BatchMetadataCacheBuilderSpec" 
-        id="shibboleth.authn.oidc.rp.BaseProviderBatchCacheBuilderSpec" abstract="true" 
-        p:parsingStrategy-ref="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataParsingStrategy"
-        p:criteriaToIdentifierStrategy-ref="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy"
-        p:sourceMetadataExpiryStrategy-ref="shibboleth.authn.oidc.rp.DefaultODICProviderSourceMetadataExpirationTimeStrategy"
-        p:identifierExtractionStrategy-ref="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy"/>
+        id="shibboleth.sp.BaseProviderBatchCacheBuilderSpec" abstract="true" 
+        p:parsingStrategy-ref="shibboleth.sp.DefaultOIDCProviderMetadataParsingStrategy"
+        p:criteriaToIdentifierStrategy-ref="shibboleth.sp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy"
+        p:sourceMetadataExpiryStrategy-ref="shibboleth.sp.DefaultODICProviderSourceMetadataExpirationTimeStrategy"
+        p:identifierExtractionStrategy-ref="shibboleth.sp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy"/>
          
     <bean class="net.shibboleth.oidc.metadata.cache.impl.DynamicMetadataCacheBuilderSpec" 
-        id="shibboleth.authn.oidc.rp.BaseProviderDynamicCacheBuilderSpec" abstract="true"        
-        p:fetchStrategy-ref="shibboleth.authn.oidc.rp.DefaultHTTPProviderConfigurationMetadataFetchingStrategy" 
-        p:criteriaToIdentifierStrategy-ref="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy" 
-        p:metadataExpirationTimeStrategy-ref="shibboleth.authn.oidc.rp.DefaultODICProviderMetadataExpirationTimeStrategy" 
-        p:identifierExtractionStrategy-ref="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy" 
+        id="shibboleth.sp.BaseProviderDynamicCacheBuilderSpec" abstract="true"        
+        p:fetchStrategy-ref="shibboleth.sp.DefaultHTTPProviderConfigurationMetadataFetchingStrategy" 
+        p:criteriaToIdentifierStrategy-ref="shibboleth.sp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy" 
+        p:metadataExpirationTimeStrategy-ref="shibboleth.sp.DefaultODICProviderMetadataExpirationTimeStrategy" 
+        p:identifierExtractionStrategy-ref="shibboleth.sp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy" 
        />
 
 
     <!-- Common parents for cache strategy implementations -->
     
-    <bean id="shibboleth.authn.oidc.rp.ProviderConfigurationMetadataFileLoadingStrategy"
+    <bean id="shibboleth.sp.ProviderConfigurationMetadataFileLoadingStrategy"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultFileLoadingStrategy" abstract="true"/>
     
     <!-- Common implementation strategies for cache implementations -->
    
-    <bean id="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataParsingStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultOIDCProviderMetadataParsingStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultOIDCProviderMetadataParsingStrategy" />
         
-    <bean id="shibboleth.authn.oidc.rp.DefaultMapParsingStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultMapParsingStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultJSONMapParsingStrategy" />
 
-    <bean id="shibboleth.authn.oidc.rp.DefaultODICProviderMetadataExpirationTimeStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultODICProviderMetadataExpirationTimeStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultOIDCProviderMetadataExpirationTimeStrategy"/>
     
-    <bean id="shibboleth.authn.oidc.rp.DefaultODICProviderSourceMetadataExpirationTimeStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultODICProviderSourceMetadataExpirationTimeStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultSourceMetadataExpirationTimeStrategy"
         c:duration="PT10M" />
 
-    <bean id="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultOIDCProviderMetadataIdentifierExtractionStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultOIDCProviderMetadataIdentifierExtractionStrategy" />
 
-    <bean id="shibboleth.authn.oidc.rp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy" scope="prototype"
+    <bean id="shibboleth.sp.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy" scope="prototype"
         class="net.shibboleth.oidc.metadata.cache.impl.DefaultOIDCProviderMetadataCriteriaToIdentifierStrategy" />
 
 
diff --git a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCSessionInitiatorFlowTest.java b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCSessionInitiatorFlowTest.java
index ad0a75a..9e8405c 100644
--- a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCSessionInitiatorFlowTest.java
+++ b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCSessionInitiatorFlowTest.java
@@ -17,6 +17,7 @@ package net.shibboleth.sp.oidc.flows;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
 
 import java.io.IOException;
 import java.net.URI;
@@ -28,22 +29,31 @@ import java.util.Map;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.mockito.Mockito;
 import org.opensaml.messaging.decoder.MessageDecodingException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.binding.SAMLBindingSupport;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.web.WebAppConfiguration;
 import org.springframework.util.ObjectUtils;
 import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 import org.springframework.webflow.executor.FlowExecutionResult;
 import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.PlainJWT;
 import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
 import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 
 import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
 import net.shibboleth.idp.test.PreferFileSystemApplicationContextInitializer;
@@ -80,6 +90,12 @@ public class OIDCSessionInitiatorFlowTest extends AbstractSPFlowTest {
     
     /** REDIRECT URI. */
     @Nonnull public static final String RESPONSE_URL = "https://sp.example.org/Shibboleth.sso/callback";
+    
+    /** The mocked HttpClient to use when responding to Token and UserInfo requests.*/
+    private HttpClient httpClient;
+    
+    /** The OP metadata to use.*/
+    private OIDCProviderMetadata metadata;
 
 
     /** Constructor. */
@@ -87,6 +103,50 @@ public class OIDCSessionInitiatorFlowTest extends AbstractSPFlowTest {
         super(FLOW_ID);
     }
     
+    /** 
+     * Pre-test work.
+     *  
+     * @throws Exception on error
+     */
+    @BeforeMethod
+    public void beforeMethod() throws Exception {
+        setDefaultAuth();
+        final ApplicationContext applicationContext2 = applicationContext;
+        if (applicationContext2 != null) {
+            httpClient = applicationContext2.getBean("Mock.HttpClient", HttpClient.class);
+        } else {
+            fail("Mocked Http Client could not be found");
+        }
+        if (httpClient == null) {
+            fail("Mocked Http Client could not be found");
+        }
+        // Add a default metadata response
+        final var metadataFromFile = new ClassPathResource("metadata/openid-configuration.json");
+        final String json = new String(metadataFromFile.getInputStream().readAllBytes(), StandardCharsets.UTF_8);        
+        metadata = OIDCProviderMetadata.parse(JSONObjectUtils.parse(json));        
+        mockProviderMetadataEndpoint(metadata);
+        
+    }
+    
+    /**
+     * Mock OpenID Provider configuration (metadata) endpoint.
+     * 
+     * @param tokenResponse the token response
+     * @param userInfoResponse the user info response
+     * 
+     * @throws IOException on error.
+     */
+    private void mockProviderMetadataEndpoint(final OIDCProviderMetadata metadata) throws IOException {
+        
+        Mockito.when(httpClient.execute(
+                Mockito.argThat(req -> req != null && req.getRequestUri().toString()
+                .contains(".well-known/openid-configuration")),
+                Mockito.any(HttpContext.class),
+                Mockito.any(HttpClientResponseHandler.class)))
+            .thenReturn(metadata);
+
+    }
+
     /**
      * Basic flow test.
      * 
diff --git a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCTokenConsumerFlowTest.java b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCTokenConsumerFlowTest.java
index cc58fb5..cf2062c 100644
--- a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCTokenConsumerFlowTest.java
+++ b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCTokenConsumerFlowTest.java
@@ -51,6 +51,7 @@ import org.opensaml.saml.saml2.core.NameIDType;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.web.WebAppConfiguration;
 import org.springframework.webflow.executor.FlowExecutionResult;
@@ -72,11 +73,13 @@ import com.nimbusds.oauth2.sdk.id.State;
 import com.nimbusds.oauth2.sdk.token.AccessToken;
 import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
 import com.nimbusds.oauth2.sdk.token.RefreshToken;
+import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
 import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
 import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
 import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
 import com.nimbusds.openid.connect.sdk.UserInfoSuccessResponse;
 import com.nimbusds.openid.connect.sdk.claims.UserInfo;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
 
 import net.minidev.json.JSONObject;
@@ -125,15 +128,22 @@ public class OIDCTokenConsumerFlowTest extends AbstractSPFlowTest {
     
     /** The mocked HttpClient to use when responding to Token and UserInfo requests.*/
     private HttpClient httpClient;
+    
+    /** The OP metadata to use.*/
+    private OIDCProviderMetadata metadata;
 
     /** Constructor. */
     public OIDCTokenConsumerFlowTest() {
         super(TestConstants.FLOW_ID);
     }
     
-    /** Pre-test work. */
+    /** 
+     * Pre-test work.
+     *  
+     * @throws Exception on error
+     */
     @BeforeMethod
-    public void beforeMethod() {
+    public void beforeMethod() throws Exception{
         setDefaultAuth();
         final ApplicationContext applicationContext2 = applicationContext;
         if (applicationContext2 != null) {
@@ -144,6 +154,10 @@ public class OIDCTokenConsumerFlowTest extends AbstractSPFlowTest {
         if (httpClient == null) {
             fail("Mocked Http Client could not be found");
         }
+        // Add a default metadata response
+        final var metadataFromFile = new ClassPathResource("metadata/openid-configuration.json");
+        final String json = new String(metadataFromFile.getInputStream().readAllBytes(), StandardCharsets.UTF_8);        
+        metadata = OIDCProviderMetadata.parse(JSONObjectUtils.parse(json));        
         
     }
     
@@ -704,6 +718,13 @@ public class OIDCTokenConsumerFlowTest extends AbstractSPFlowTest {
     private void mockOIDCEndpoints(final OIDCTokenResponse tokenResponse, 
             final UserInfoSuccessResponse userInfoResponse) throws IOException {
         
+        Mockito.when(httpClient.execute(
+                Mockito.argThat(req -> req != null && req.getRequestUri().toString()
+                .contains(".well-known/openid-configuration")),
+                Mockito.any(HttpContext.class),
+                Mockito.any(HttpClientResponseHandler.class)))
+            .thenReturn(metadata);
+        
         Mockito.when(httpClient.execute(
                 Mockito.argThat(req -> req != null && req.getRequestUri().toString().contains("/token")),
                 Mockito.any(HttpContext.class),
diff --git a/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-metadata-providers.xml b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-metadata-providers.xml
new file mode 100644
index 0000000..fb883bc
--- /dev/null
+++ b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-metadata-providers.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+    default-init-method="initialize" default-destroy-method="destroy">
+    
+    <!-- 
+        The default metadata provider fetches OpenID Provider configuration metadata from the issuers well-known 
+        location. 
+    -->
+    <util:list id="shibboleth.sp.ProviderMetadataResolvers">
+        <ref bean="ProviderHTTPResolver" />
+    </util:list>
+
+    <bean id="ProviderHTTPResolver" parent="shibboleth.sp.OIDCProviderMetadataResolver">
+        <constructor-arg>
+            <bean parent="shibboleth.sp.CacheBuilder">
+                <constructor-arg>
+                    <bean p:cacheId="ProviderHTTPDynamicResolver" 
+                    parent="shibboleth.sp.BaseProviderDynamicCacheBuilderSpec" 
+                    p:minCacheDuration="PT5S"
+                    p:maxCacheDuration="PT10S"
+                    p:cleanupTaskInterval="PT30M"/>
+                </constructor-arg>
+            </bean>
+        </constructor-arg>
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test-agents.xml b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test-agents.xml
index d6e7c7b..e227f93 100644
--- a/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test-agents.xml
+++ b/sp-oidc-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/oidc-test-agents.xml
@@ -22,20 +22,16 @@
         p:issuer="testsp.example.org">
         <property name="applications">
             <set>
-                <bean p:id="test-oidc-application-with-default-profile" parent="shibboleth.sp.Application"
-                    p:metadataResolver-ref="shibboleth.ProviderMetadataResolverService"/>
+                <bean p:id="test-oidc-application-with-default-profile" parent="shibboleth.sp.Application"/>
                     
                 <bean p:id="test-oidc-application-without-ro" parent="shibboleth.sp.Application"
-                    p:profileConfigurations-ref="test.ProfileConfigurations" 
-                    p:metadataResolver-ref="shibboleth.ProviderMetadataResolverService"/>
+                    p:profileConfigurations-ref="test.ProfileConfigurations"/>
                     
                 <bean p:id="test-oidc-application-with-ro" parent="shibboleth.sp.Application"
-                    p:profileConfigurations-ref="test.RequestObjectProfileConfigurations" 
-                    p:metadataResolver-ref="shibboleth.ProviderMetadataResolverService"/>
+                    p:profileConfigurations-ref="test.RequestObjectProfileConfigurations"/>
                     
                 <bean p:id="test-oidc-application-with-ro-with-requested-attrs" parent="shibboleth.sp.Application"
-                    p:profileConfigurations-ref="test.RequestedClaimsProfileConfigurations" 
-                    p:metadataResolver-ref="shibboleth.ProviderMetadataResolverService"/>
+                    p:profileConfigurations-ref="test.RequestedClaimsProfileConfigurations"/>
             </set>
         </property>
     </bean>
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/metadata/impl/ApplicationMetadataResolverLookupFunction.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ApplicationMetadataResolverLookupFunction.java
similarity index 52%
rename from sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/metadata/impl/ApplicationMetadataResolverLookupFunction.java
rename to sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ApplicationMetadataResolverLookupFunction.java
index bf164fa..58512fd 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/metadata/impl/ApplicationMetadataResolverLookupFunction.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ApplicationMetadataResolverLookupFunction.java
@@ -12,31 +12,25 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.oidc.metadata.impl;
-
-import java.io.IOException;
+package net.shibboleth.sp.oidc.profile.impl;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.saml.metadata.resolver.MetadataResolver;
 import org.slf4j.Logger;
-import org.springframework.core.io.ClassPathResource;
 
 import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
-import net.shibboleth.oidc.metadata.impl.FilesystemProviderMetadataResolver;
+import net.shibboleth.oidc.metadata.impl.ReloadingProviderMetadataProvider;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.Application;
 import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.oidc.OIDCProtocolSupportService;
 import net.shibboleth.sp.profile.context.navigate.messaging.AbstractAgentRequestLookupFunction;
 
 /**
- * Locates the {@link MetadataResolver} associated with the {@link Application} making an agent request,
- * and wraps it in a {@link ProviderMetadataResolver}.
- * 
- * TODO I think this will eventually exist in the SP core and be more generic.
+ * Locates the {@link ProviderMetadataResolver} associated with the {@link Application} making an agent request.
  */
 public class ApplicationMetadataResolverLookupFunction
         extends AbstractAgentRequestLookupFunction<ProviderMetadataResolver> {
@@ -51,29 +45,26 @@ public class ApplicationMetadataResolverLookupFunction
             final Application application = arc.getApplication();
             if (application != null) {
                 try {
-//                    final ReloadingProviderMetadataProvider metadataResolver =
-//                            new ReloadingProviderMetadataProvider(application.getMetadataResolver());
-//                    metadataResolver.setId(application.getId() + " MetadataResolver");
-//                    metadataResolver.initialize();
-//                    
-//                    final ProviderMetadataResolver roleResolver =
-//                            new ProviderMetadataResolver(metadataResolver);
-//                    roleResolver.initialize();
-                    
-                    // FIXME, this will need changing over once supported to take from Application
-                    final FilesystemProviderMetadataResolver fsr = 
-                            new FilesystemProviderMetadataResolver(
-                                    new ClassPathResource("metadata/openid-configuration.json"));
-                    fsr.setId(application.getId() + " MetadataResolver");
-                    fsr.initialize();
+                    final OIDCProtocolSupportService supportService = 
+                            application.getProtocolSupportService(OIDCProtocolSupportService.PROTOCOL_ID, 
+                                    OIDCProtocolSupportService.class);
                     
-                    return fsr;
-                } catch (final IOException | ComponentInitializationException e) {
-                    log.error("Exception wrapping Application-supplied MetadataResolver for use", e);
+                    if (supportService != null) {
+                        final ReloadingProviderMetadataProvider metadataResolver =
+                                new ReloadingProviderMetadataProvider(supportService.getMetadataResolver());
+                        metadataResolver.setId(application.getId() + " MetadataResolver");
+                        metadataResolver.initialize();
+                        return metadataResolver;
+                    } else {
+                        log.warn("Application did not supply an OIDC ProtocolSupportService instance");
+                    }
+                } catch (final ComponentInitializationException e) {
+                    log.error("Exception wrapping Application-supplied ProviderMetadataResolver for use", e);
                 }
+            } else {
+                log.warn("Application was not available to acquire necessary services");
             }
-        }
-        
+        }       
         return null;
     }
 
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ExtractOIDCClaims.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ExtractOIDCClaims.java
index ff33cab..dd5ae6d 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ExtractOIDCClaims.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ExtractOIDCClaims.java
@@ -28,7 +28,6 @@ import org.opensaml.messaging.context.navigate.RecursiveTypedParentContextLookup
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.saml.metadata.resolver.MetadataResolver;
 import org.slf4j.Logger;
 
 import com.google.common.collect.HashMultimap;
@@ -53,6 +52,7 @@ import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
 import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
 import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
 import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.metadata.ProviderMetadataResolver;
 import net.shibboleth.oidc.profile.config.OIDCSSORelyingPartyConfiguration;
 import net.shibboleth.oidc.profile.context.EndUserClaimsContext;
 import net.shibboleth.profile.context.RelyingPartyContext;
@@ -68,6 +68,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.service.ServiceException;
 import net.shibboleth.shared.service.ServiceableComponent;
 import net.shibboleth.sp.Application;
+import net.shibboleth.sp.oidc.OIDCProtocolSupportService;
 import net.shibboleth.sp.profile.AbstractApplicationAction;
 
 /**
@@ -376,15 +377,26 @@ public class ExtractOIDCClaims extends AbstractApplicationAction {
         populateFilterContext(profileRequestContext, filterContext);
         
         try (final ServiceableComponent<AttributeFilter> filterComponent =
-                ensureApplication().getAttributeFilter().getServiceableComponent();
-                final ServiceableComponent<MetadataResolver> metadataResolverComponent =
-                        ensureApplication().getMetadataResolver().getServiceableComponent()) {
+                ensureApplication().getAttributeFilter().getServiceableComponent()) {
             
-            // TODO, can only use SAML metadata here. Populate here for locking scope.
-            //filterContext.setMetadataResolver(metadataResolverComponent.getComponent());
+            final OIDCProtocolSupportService supportService = 
+                    ensureApplication().getProtocolSupportService(OIDCProtocolSupportService.PROTOCOL_ID, 
+                            OIDCProtocolSupportService.class);
             
-            final AttributeFilter filter = filterComponent.getComponent();
-            filter.filterAttributes(filterContext);
+            if (supportService != null) {
+                try (final ServiceableComponent<ProviderMetadataResolver> metadataComponent =
+                        supportService.getMetadataResolver().getServiceableComponent()) {
+                    // TODO, can only use SAML metadata here. Populate here for locking scope.
+                    //filterContext.setMetadataResolver(metadataResolverComponent.getComponent());
+                    final AttributeFilter filter = filterComponent.getComponent();
+                    filter.filterAttributes(filterContext);
+                } catch (final ServiceException e) {
+                    log.error("{} Invalid ProviderMetadataResolver configuration", getLogPrefix(), e);
+                }
+            } else {
+                final AttributeFilter filter = filterComponent.getComponent();
+                filter.filterAttributes(filterContext);
+            }
             filterContext.removeFromParent();
             attributeContext.setIdPAttributes(filterContext.getFilteredIdPAttributes());
         } catch (final AttributeFilterException e) {

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


More information about the commits mailing list