[java-plugin-shibd-saml] branch main updated: JSHIBD-7 - Decompose Application layer to avoid protocol dependencies

Codeberg noreply at shibboleth.net
Thu Feb 5 19:36:39 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-saml.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-saml/commit/938713b955db6bfe205183d8f41c67607d7c078e

The following commit(s) were added to refs/heads/main by this push:
     new 938713b  JSHIBD-7 - Decompose Application layer to avoid protocol dependencies
938713b is described below

commit 938713b955db6bfe205183d8f41c67607d7c078e
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Feb 5 14:32:20 2026 -0500

    JSHIBD-7 - Decompose Application layer to avoid protocol dependencies
    
    https://shibboleth.atlassian.net/browse/JSHIBD-7
    
    Implement SAML-specific ProtocolSupportService code.
    Migrate MetadataResolver dependencies to new API.
---
 .../saml2/BasicSAML2ProtocolSupportService.java    | 62 +++++++++++++++++
 .../sp/saml/saml2/SAML2ProtocolSupportService.java | 41 +++++++++++
 .../net/shibboleth/sp/saml/saml2/package-info.java | 18 +++++
 .../shibboleth/idp/flows/sp/saml2-common-beans.xml |  2 +-
 .../net/shibboleth/sp/service/agent/postconfig.xml |  3 +-
 sp-saml-impl/pom.xml                               |  5 ++
 .../ApplicationMetadataResolverLookupFunction.java | 79 ++++++++++++++++++++++
 .../saml2/profile/impl/ExtractSAMLAttributes.java  | 26 +++++--
 8 files changed, 227 insertions(+), 9 deletions(-)

diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/BasicSAML2ProtocolSupportService.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/BasicSAML2ProtocolSupportService.java
new file mode 100644
index 0000000..91b416a
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/BasicSAML2ProtocolSupportService.java
@@ -0,0 +1,62 @@
+/*
+ * 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.saml.saml2;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+
+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;
+
+/**
+ * Basic implementation of {@link SAML2ProtocolSupportService}.
+ */
+public class BasicSAML2ProtocolSupportService extends BasicProtocolSupportService
+    implements SAML2ProtocolSupportService {
+
+    /** Metadata source. */
+    @NonnullAfterInit private ReloadableService<MetadataResolver> metadataResolver;
+    
+    
+    /** [{@inheritDoc} */
+    @NonnullAfterInit public ReloadableService<MetadataResolver> getMetadataResolver() {
+        return metadataResolver;
+    }
+    
+    /**
+     * Sets the {@link MetadataResolver} to use.
+     * 
+     * @param service metadata resolver service
+     */
+    public void setMetadataResolver(@Nonnull final ReloadableService<MetadataResolver> service) {
+        checkSetterPreconditions();
+        
+        metadataResolver = Constraint.isNotNull(service, "MetadataResolver service cannot be null");
+    }
+ 
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        
+        if (metadataResolver == null) {
+            throw new ComponentInitializationException("MetadataResolver cannot be null");
+        }
+    }
+    
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/SAML2ProtocolSupportService.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/SAML2ProtocolSupportService.java
new file mode 100644
index 0000000..21b7cee
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/SAML2ProtocolSupportService.java
@@ -0,0 +1,41 @@
+/*
+ * 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.saml.saml2;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+
+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;
+
+/**
+ * SAML 2 subinterface of {@link ProtocolSupportService} to any add SAML-specific features or services.
+ */
+public interface SAML2ProtocolSupportService extends ProtocolSupportService {
+
+    /** Key of map entry for this subtype. */
+    @Nonnull @NotEmpty static String PROTOCOL_ID = "SAML2";
+    
+    /**
+     * Gets the default {@link MetadataResolver} service to use.
+     * 
+     * @return service to use
+     */
+    @NonnullAfterInit ReloadableService<MetadataResolver> getMetadataResolver();
+
+}
\ No newline at end of file
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/package-info.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/package-info.java
new file mode 100644
index 0000000..093a696
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/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 SAML 2.0 protocol support in the SP Hub.
+ */
+package net.shibboleth.sp.saml.saml2;
\ No newline at end of file
diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/saml2-common-beans.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/saml2-common-beans.xml
index 41434c7..75423c6 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/saml2-common-beans.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/saml2-common-beans.xml
@@ -39,7 +39,7 @@
         <constructor-arg name="messageHandler">
             <bean class="org.opensaml.saml.common.binding.impl.SAMLMetadataLookupHandler" scope="prototype">
                 <property name="roleDescriptorResolverLookupStrategy">
-                    <bean class="net.shibboleth.sp.profile.context.navigate.messaging.ApplicationMetadataResolverLookupFunction" />
+                    <bean class="net.shibboleth.sp.saml.saml2.profile.impl.ApplicationMetadataResolverLookupFunction" />
                 </property>
             </bean>
         </constructor-arg>
diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
index 1bae617..3922a3a 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/sp/service/agent/postconfig.xml
@@ -18,9 +18,10 @@
 <!--     <import resource="agents-system-mddriven.xml" /> -->
 
     <!-- Auto-wired protocol service support bean for use by parent plugin. -->
-    <bean class="net.shibboleth.sp.BasicProtocolSupportService"
+    <bean class="net.shibboleth.sp.saml.saml2.BasicSAML2ProtocolSupportService"
             p:id="SAML2"
             p:order="%{sp.saml.relativeOrder:1}"
+            p:metadataResolver-ref="shibboleth.MetadataResolverService"
             p:sessionInitiators="saml2"
             p:tokenConsumers="#{{ 'saml2/post', 'saml2/post-simplesign', 'saml2/artifact' }}">
         <property name="defaultProfileConfigurations">
diff --git a/sp-saml-impl/pom.xml b/sp-saml-impl/pom.xml
index c679775..e6be3ba 100644
--- a/sp-saml-impl/pom.xml
+++ b/sp-saml-impl/pom.xml
@@ -82,6 +82,11 @@
             <artifactId>shib-metadata-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>${shib-metadata.groupId}</groupId>
+            <artifactId>shib-metadata-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
         
         <dependency>
             <groupId>${opensaml.groupId}</groupId>
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ApplicationMetadataResolverLookupFunction.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ApplicationMetadataResolverLookupFunction.java
new file mode 100644
index 0000000..87e644d
--- /dev/null
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ApplicationMetadataResolverLookupFunction.java
@@ -0,0 +1,79 @@
+/*
+ * 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.saml.saml2.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.opensaml.saml.metadata.resolver.RoleDescriptorResolver;
+import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.saml.metadata.impl.ReloadableMetadataResolver;
+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.profile.context.navigate.messaging.AbstractAgentRequestLookupFunction;
+import net.shibboleth.sp.saml.saml2.SAML2ProtocolSupportService;
+
+/**
+ * Locates the {@link MetadataResolver} associated with the {@link Application} making an agent request,
+ * and wraps it in a {@link RoleDescriptorResolver}.
+ */
+public class ApplicationMetadataResolverLookupFunction
+        extends AbstractAgentRequestLookupFunction<RoleDescriptorResolver> {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ApplicationMetadataResolverLookupFunction.class);
+    
+    /** {@inheritDoc} */
+    @Nullable public RoleDescriptorResolver apply(@Nullable final MessageContext input) {
+        final AgentRequestContext arc = getAgentRequestContext(input);
+        if (arc != null) {
+            final Application application = arc.getApplication();
+            if (application != null) {
+                try {
+                    final SAML2ProtocolSupportService supportService =
+                            application.getProtocolSupportService(SAML2ProtocolSupportService.PROTOCOL_ID,
+                                    SAML2ProtocolSupportService.class);
+                    if (supportService != null) {
+                        final ReloadableMetadataResolver metadataResolver =
+                                new ReloadableMetadataResolver(supportService.getMetadataResolver());
+                        metadataResolver.setId(application.getId() + " MetadataResolver");
+                        metadataResolver.initialize();
+                        
+                        final PredicateRoleDescriptorResolver roleResolver =
+                                new PredicateRoleDescriptorResolver(metadataResolver);
+                        roleResolver.initialize();
+                        
+                        return roleResolver;
+                    } else {
+                        log.warn("Application did not supply a SAML 2 ProtocolSupportService instance");
+                    }
+                } catch (final ComponentInitializationException e) {
+                    log.error("Exception wrapping Application-supplied MetadataResolver for use", e);
+                }
+            } else {
+                log.warn("Application was not available to acquire necessary services");
+            }
+        }
+        
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
index 8d6dbf0..7a327df 100644
--- a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ExtractSAMLAttributes.java
@@ -86,6 +86,7 @@ import net.shibboleth.shared.service.ServiceException;
 import net.shibboleth.shared.service.ServiceableComponent;
 import net.shibboleth.sp.Application;
 import net.shibboleth.sp.profile.AbstractApplicationAction;
+import net.shibboleth.sp.saml.saml2.SAML2ProtocolSupportService;
 import net.shibboleth.sp.saml.saml2.context.SAMLTokenContext;
 import net.shibboleth.sp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
 
@@ -480,15 +481,26 @@ public class ExtractSAMLAttributes extends AbstractApplicationAction {
         populateFilterContext(profileRequestContext, filterContext);
         
         try (final ServiceableComponent<AttributeFilter> filterComponent =
-                ensureApplication().getAttributeFilter().getServiceableComponent();
-                final ServiceableComponent<MetadataResolver> metadataResolverComponent =
-                        ensureApplication().getMetadataResolver().getServiceableComponent()) {
+                ensureApplication().getAttributeFilter().getServiceableComponent()) {
 
-            // Populate here for locking scope.
-            filterContext.setMetadataResolver(metadataResolverComponent.getComponent());
+            // We have to fork here based on whether we can access a MetadataResolver.
+            
+            final SAML2ProtocolSupportService supportService = ensureApplication().getProtocolSupportService(
+                    SAML2ProtocolSupportService.PROTOCOL_ID, SAML2ProtocolSupportService.class);
+            if (supportService != null) {
+                try (final ServiceableComponent<MetadataResolver> metadataComponent =
+                        supportService.getMetadataResolver().getServiceableComponent()) {
+                    filterContext.setMetadataResolver(metadataComponent.getComponent());
+                    final AttributeFilter filter = filterComponent.getComponent();
+                    filter.filterAttributes(filterContext);
+                } catch (final ServiceException e) {
+                    log.error("{} Invalid MetadataResolver configuration", getLogPrefix(), e);
+                }
+            } else {
+                final AttributeFilter filter = filterComponent.getComponent();
+                filter.filterAttributes(filterContext);
+            }
             
-            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