[java-plugin-shibd] branch main updated: JSHIBD-24 - Application and RelyingPartyConfiguration inheritance

Codeberg noreply at shibboleth.net
Mon Oct 12 21:46:49 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.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd/commit/8e04d169bcabaaa726cceda6fb70c3dd538791b9

The following commit(s) were added to refs/heads/main by this push:
     new 8e04d16  JSHIBD-24 - Application and RelyingPartyConfiguration inheritance
8e04d16 is described below

commit 8e04d169bcabaaa726cceda6fb70c3dd538791b9
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon Oct 12 17:46:32 2026 -0400

    JSHIBD-24 - Application and RelyingPartyConfiguration inheritance
    
    https://shibboleth.atlassian.net/browse/JSHIBD-24
    
    Reimplement delegation of RelyingPartyConfigurations.
    Use standard BasicRelyingPartyConfiguration objects wrapping at runtime.
---
 .../net/shibboleth/sp/conf/agents-system.xml       |  16 +-
 .../net/shibboleth/sp/impl/BasicApplication.java   |  32 ++--
 .../impl/DelegatingRelyingPartyConfiguration.java  | 103 ++++++++-----
 .../sp/impl/RelyingPartyConfigurationSupport.java  | 170 ---------------------
 4 files changed, 89 insertions(+), 232 deletions(-)

diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
index 56c72ae..dd240c6 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
@@ -107,26 +107,24 @@
         class="net.shibboleth.sp.security.config.impl.BasicHttpClientSecurityConfiguration"
         c:resolver-ref="shibboleth.sp.CredentialResolverBridge" />
 
-    <!-- We set the honor-empty flag on this so that the typical case of an empty profile map is assumed to be valid. -->
-    <bean id="DefaultUnverifiedRelyingPartyConfiguration" class="net.shibboleth.sp.impl.DelegatingRelyingPartyConfiguration"
-        p:honorEmptyProfileCollection="true"
+    <bean id="DefaultUnverifiedRelyingPartyConfiguration" class="net.shibboleth.profile.relyingparty.BasicRelyingPartyConfiguration"
         p:profileConfigurations="#{getObject('shibboleth.sp.UnverifiedProfileConfigurations') ?: getObject('UnverifiedProfileConfigurations')}" />
 
     <!-- Parent bean for arbitrary instances. -->
-    <bean id="RelyingParty" abstract="true" class="net.shibboleth.sp.impl.DelegatingRelyingPartyConfiguration" />
+    <bean id="RelyingParty" abstract="true" class="net.shibboleth.profile.relyingparty.BasicRelyingPartyConfiguration" />
 
     <!-- Parent bean for RelyingParty overrides based on activation by name(s). -->
     <bean id="RelyingPartyByName" abstract="true"
-        class="net.shibboleth.sp.impl.RelyingPartyConfigurationSupport" factory-method="byName" />
+        class="net.shibboleth.saml.relyingparty.RelyingPartyConfigurationSupport" factory-method="byName" />
 
     <!-- Parent bean for RelyingParty overrides based on activation by group or SAML affiliation. -->
     <bean id="RelyingPartyByGroup" abstract="true"
-        class="net.shibboleth.sp.impl.RelyingPartyConfigurationSupport" factory-method="byGroup"
+        class="net.shibboleth.saml.relyingparty.RelyingPartyConfigurationSupport" factory-method="byGroup"
         c:resolver-ref="shibboleth.MetadataResolver" />
 
     <!-- Parent bean for RelyingParty overrides based on activation by local containment only. -->
     <bean id="RelyingPartyByEntitiesDescriptor" abstract="true"
-            class="net.shibboleth.sp.impl.RelyingPartyConfigurationSupport" factory-method="byGroup">
+            class="net.shibboleth.saml.relyingparty.RelyingPartyConfigurationSupport" factory-method="byGroup">
         <constructor-arg name="resolver">
             <null/>
         </constructor-arg>
@@ -134,12 +132,12 @@
 
     <!-- Parent bean for RelyingParty overrides based on activation by tag. -->
     <bean id="RelyingPartyByTag" abstract="true"
-        class="net.shibboleth.sp.impl.RelyingPartyConfigurationSupport" factory-method="byTag"
+        class="net.shibboleth.saml.relyingparty.RelyingPartyConfigurationSupport" factory-method="byTag"
         c:trim="false" c:matchAll="false" />
 
     <!-- Parent bean for RelyingParty overrides based on activation by tag. -->
     <bean id="RelyingPartyByMappedTag" abstract="true"
-        class="net.shibboleth.sp.impl.RelyingPartyConfigurationSupport" factory-method="byMappedTag"
+        class="net.shibboleth.saml.relyingparty.RelyingPartyConfigurationSupport" factory-method="byMappedTag"
         c:trim="false" c:matchAll="false" />
 
     <bean id="TagCandidate" abstract="true"
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
index 7bb58dd..32097bf 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -943,13 +944,16 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
         checkSetterPreconditions();
         
         if (configs != null) {
-            configs.stream()
-                .filter(DelegatingRelyingPartyConfiguration.class::isInstance)
-                .map(DelegatingRelyingPartyConfiguration.class::cast)
-                .forEach(rpc -> {rpc.setApplication(this);});
+            final Collection<DelegatingRelyingPartyConfiguration> wrapped =
+                    configs.stream()
+                        .map(rpc -> { return new DelegatingRelyingPartyConfiguration(this, rpc, false); })
+                        .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
+            
+            relyingPartyResolver.setRelyingPartyConfigurations(wrapped);
+        } else {
+            relyingPartyResolver.setRelyingPartyConfigurations(configs);   
         }
         
-        relyingPartyResolver.setRelyingPartyConfigurations(configs);
     }
 
     /**
@@ -959,7 +963,12 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
      */
     public void setDefaultConfiguration(@Nullable final RelyingPartyConfiguration configuration) {
         checkSetterPreconditions();
-        relyingPartyResolver.setDefaultConfiguration(configuration);
+        if (configuration != null) {
+            relyingPartyResolver.setDefaultConfiguration(
+                    new DelegatingRelyingPartyConfiguration(this, configuration, false));
+        } else {
+            relyingPartyResolver.setDefaultConfiguration(configuration);
+        }
     }
 
     /**
@@ -970,12 +979,13 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
      */
     public void setUnverifiedConfiguration(@Nullable final RelyingPartyConfiguration configuration) {
         checkSetterPreconditions();
-        
-        if (configuration instanceof DelegatingRelyingPartyConfiguration del) {
-            del.setApplication(this);
+                
+        if (configuration != null) {
+            relyingPartyResolver.setUnverifiedConfiguration(
+                    new DelegatingRelyingPartyConfiguration(this, configuration, true));
+        } else {
+            relyingPartyResolver.setUnverifiedConfiguration(configuration);
         }
-        
-        relyingPartyResolver.setUnverifiedConfiguration(configuration);
     }
 
     /**
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/DelegatingRelyingPartyConfiguration.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/DelegatingRelyingPartyConfiguration.java
index af1d589..d8aaece 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/DelegatingRelyingPartyConfiguration.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/DelegatingRelyingPartyConfiguration.java
@@ -15,6 +15,7 @@
 package net.shibboleth.sp.impl;
 
 import java.util.Map;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -23,87 +24,105 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.security.config.SecurityConfiguration;
 
 import net.shibboleth.profile.config.ProfileConfiguration;
-import net.shibboleth.profile.relyingparty.BasicRelyingPartyConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
-import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.sp.Application;
 
 /**
- * Subclass of {@link BasicRelyingPartyConfiguration} that will handle absent settings
+ * Wrapper for {@link RelyingPartyConfiguration} that will handle absent settings
  * by delegating to an injected instance of {@link Application}.
  */
-public class DelegatingRelyingPartyConfiguration extends BasicRelyingPartyConfiguration {
+public class DelegatingRelyingPartyConfiguration extends AbstractIdentifiableInitializableComponent
+        implements RelyingPartyConfiguration, Predicate<ProfileRequestContext> {
 
-    /** Delegation source. */
-    @Nullable private Application application;
+    /** Inheritance source. */
+    @Nonnull private Application application;
+    
+    /** Delegation target. */
+    @Nonnull private RelyingPartyConfiguration relyingPartyConfiguration;
     
     /** Whether to treat an empty profile configuration set as a valid outcome. */
     private boolean honorEmptyProfileCollection;
     
     /**
-     * Sets the {@link Application} to delegate to.
-     * 
-     * @param app object to delegate to
+     * Constructor.
+     *
+     * @param app inheritance source
+     * @param config delegation target
+     * @param honorEmpty whether to treat empty profile configuration collection as legitimate
      */
-    public void setApplication(@Nullable final Application app) {
-        application = app;
+    public DelegatingRelyingPartyConfiguration(@Nonnull final Application app,
+            @Nonnull final RelyingPartyConfiguration config, final boolean honorEmpty) {
+        application = Constraint.isNotNull(app, "Application cannot be null");
+        relyingPartyConfiguration = Constraint.isNotNull(config, "RelyingPartyConfiguration cannot be null");
+        honorEmptyProfileCollection = honorEmpty;
     }
-    
-    /**
-     * Sets whether to treat an empty collection returned by {@link #getProfileConfigurations(ProfileRequestContext)}
-     * as a valid outcome, thus not forwarding the lookup on to the injected {@link Application}.
-     * 
-     * <p>Defaults to false, disallowing an empty collection as an expected result.</p>
-     * 
-     * @param flag flag to set
-     */
-    public void setHonorEmptyProfileCollection(final boolean flag) {
-        checkSetterPreconditions();
-        honorEmptyProfileCollection = flag;
+     
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public String getId() {
+        return relyingPartyConfiguration.getId();
+    }
+
+    /** {@inheritDoc} */
+    public boolean test(@Nullable final ProfileRequestContext input) {
+        return relyingPartyConfiguration.test(input);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("removal")
+    public void setResponderId(@Nullable final String issuer) {
+        relyingPartyConfiguration.setResponderId(issuer);
     }
     
     /** {@inheritDoc} */
-    @Override
     @Nullable public String getIssuer(@Nullable final ProfileRequestContext profileRequestContext) {
-        final String issuer = super.getIssuer(profileRequestContext);
+        final String issuer = relyingPartyConfiguration.getIssuer(profileRequestContext);
         if (issuer != null) {
             return issuer;
-        } else if (application != null) {
-            return application.getIssuer(profileRequestContext);
-        } else {
-            return null;
         }
+        return application.getIssuer(profileRequestContext);
     }
 
     /** {@inheritDoc} */
-    @Override
     @Nullable public SecurityConfiguration getSecurityConfiguration(
             @Nullable final ProfileRequestContext profileRequestContext) {
         
-        final SecurityConfiguration config = super.getSecurityConfiguration(profileRequestContext);
+        final SecurityConfiguration config = relyingPartyConfiguration.getSecurityConfiguration(profileRequestContext);
         if (config != null) {
             return config;
-        } else if (application != null) {
-            return application.getSecurityConfiguration(profileRequestContext);
-        } else {
-            return null;
         }
+        return application.getSecurityConfiguration(profileRequestContext);
     }
 
     /** {@inheritDoc} */
-    @Override
-    @Nonnull @Unmodifiable @NotLive public Map<String, ProfileConfiguration> getProfileConfigurations(
+    @Nonnull @Unmodifiable @NotLive public Map<String,ProfileConfiguration> getProfileConfigurations(
             @Nullable final ProfileRequestContext profileRequestContext) {
         
-        final var profiles = super.getProfileConfigurations(profileRequestContext);
+        final var profiles = relyingPartyConfiguration.getProfileConfigurations(profileRequestContext);
         if (honorEmptyProfileCollection || !profiles.isEmpty()) {
             return profiles;
-        } else if (application != null) {
-            return application.getProfileConfigurations(profileRequestContext);
-        } else {
-            return CollectionSupport.emptyMap();
         }
+        return application.getProfileConfigurations(profileRequestContext);
+    }
+
+    /** {@inheritDoc} */
+    public ProfileConfiguration getProfileConfiguration(ProfileRequestContext profileRequestContext, String profileId) {
+        final String trimmedId = StringSupport.trimOrNull(profileId);
+        if (trimmedId == null) {
+            return null;
+        }
+
+        return getProfileConfigurations(profileRequestContext).get(trimmedId);
+    }
+    
+    /** {@inheritDoc} */
+    public boolean isDetailedErrors(ProfileRequestContext profileRequestContext) {
+        return relyingPartyConfiguration.isDetailedErrors(profileRequestContext);
     }
 
 }
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/RelyingPartyConfigurationSupport.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/RelyingPartyConfigurationSupport.java
deleted file mode 100644
index a3d26ea..0000000
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/RelyingPartyConfigurationSupport.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.impl;
-
-import java.util.Collection;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.saml.common.messaging.context.navigate.EntityDescriptorLookupFunction;
-import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate;
-import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate.Candidate;
-import org.opensaml.saml.common.profile.logic.EntityGroupNamePredicate;
-import org.opensaml.saml.metadata.resolver.MetadataResolver;
-import org.opensaml.saml.saml2.metadata.AffiliationDescriptor;
-import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
-import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-
-import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
-import net.shibboleth.profile.context.logic.RelyingPartyIdPredicate;
-import net.shibboleth.saml.profile.context.logic.MappedEntityAttributesPredicate;
-import net.shibboleth.saml.profile.context.navigate.SAMLMetadataContextLookupFunction;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.logic.StrategyIndirectedPredicate;
-
-/**
- * This is a duplicate of a higher level class in order to override the "type" of the
- * {@link RelyingPartyConfiguration} to create.
- * 
- * // TODO: adjust the original class to support overriding type creation somehow 
- */
-public final class RelyingPartyConfigurationSupport {
-    
-    /** Constructor. */
-    private RelyingPartyConfigurationSupport() {
-        
-    }
-    
-    /**
-     * A shorthand method for constructing a {@link RelyingPartyConfiguration} with an activation condition
-     * based on one or more relying party IDs.
-     * 
-     * <p>If a single ID is supplied, then the ID is also set as the identifier for the configuration.</p>
-     * 
-     * @param relyingPartyIds the relying parties for which the configuration should be active
-     * 
-     * @return  a default-constructed configuration with the appropriate condition set
-     */
-    @Nonnull public static RelyingPartyConfiguration byName(@Nonnull final Collection<String> relyingPartyIds) {
-
-        Constraint.isNotNull(relyingPartyIds, "Relying Party ID list cannot be null");
-
-        final DelegatingRelyingPartyConfiguration config = new DelegatingRelyingPartyConfiguration(); 
-        config.setActivationCondition(new RelyingPartyIdPredicate(relyingPartyIds));
-        
-        final StringBuffer name = new StringBuffer("EntityNames[");
-        for (final String rpId: relyingPartyIds) {
-            name.append(rpId).append(',');
-            
-        }
-        name.append(']');
-        config.setId(name.toString());
-        return config;
-    }
-
-    /**
-     * A shorthand method for constructing a {@link RelyingPartyConfiguration} with an activation condition
-     * based on one or more {@link EntitiesDescriptor} groups, and optionally via {@link AffiliationDescriptor} lookup.
-     * 
-     * @param groupNames the group names
-     * @param resolver optional metadata source for affiliation lookup
-     * 
-     * @return  a default-constructed configuration with the appropriate condition set
-     */
-    @Nonnull public static RelyingPartyConfiguration byGroup(@Nonnull final Collection<String> groupNames,
-            @Nullable final MetadataResolver resolver) {
-        Constraint.isNotNull(groupNames, "Group name list cannot be null");
-        
-        // We adapt an OpenSAML Predicate applying to an EntityDescriptor by indirecting the lookup of the
-        // EntityDescriptor to a lookup sequence of PRC -> RPC -> SAMLMetadataContext -> EntityDescriptor.
-        
-        final StrategyIndirectedPredicate<ProfileRequestContext,EntityDescriptor> indirectPredicate =
-                new StrategyIndirectedPredicate<>(
-                        new EntityDescriptorLookupFunction().compose(new SAMLMetadataContextLookupFunction()),
-                        new EntityGroupNamePredicate(groupNames, resolver));
-        
-        final DelegatingRelyingPartyConfiguration config = new DelegatingRelyingPartyConfiguration(); 
-        config.setActivationCondition(indirectPredicate);
-
-        final StringBuffer name = new StringBuffer("EntityGroups[");
-        for (final String group: groupNames) {
-            name.append(group).append(',');
-            
-        }
-        name.append(']');
-        config.setId(name.toString());
-        return config;
-    }
-
-    
-    /**
-     * A shorthand method for constructing a {@link RelyingPartyConfiguration} with an activation condition
-     * based on an {@link EntityAttributesPredicate}.
-     * 
-     * @param candidates the candidate rules
-     * @param trim true iff tag values in metadata should be trimmed before comparison
-     * @param matchAll true iff all the candidate rules are required to match
-     * 
-     * @return  a default-constructed configuration with the appropriate condition set
-     */
-    @Nonnull public static RelyingPartyConfiguration byTag(@Nonnull final Collection<Candidate> candidates,
-            final boolean trim, final boolean matchAll) {
-        Constraint.isNotNull(candidates, "Candidate list cannot be null");
-        
-        // We adapt an OpenSAML Predicate applying to an EntityDescriptor by indirecting the lookup of the
-        // EntityDescriptor to a lookup sequence of PRC -> RPC -> SAMLMetadataContext -> EntityDescriptor.
-        
-        final StrategyIndirectedPredicate<ProfileRequestContext,EntityDescriptor> indirectPredicate =
-                new StrategyIndirectedPredicate<>(
-                        new EntityDescriptorLookupFunction().compose(new SAMLMetadataContextLookupFunction()),
-                        new EntityAttributesPredicate(candidates, trim, matchAll));
-        
-        final DelegatingRelyingPartyConfiguration config = new DelegatingRelyingPartyConfiguration(); 
-        config.setActivationCondition(indirectPredicate);
-
-        return config;
-    }
-
-    /**
-     * A shorthand method for constructing a {@link RelyingPartyConfiguration} with an activation condition
-     * based on a {@link MappedEntityAttributesPredicate}.
-     * 
-     * @param candidates the candidate rules
-     * @param trim true iff tag values in metadata should be trimmed before comparison
-     * @param matchAll true iff all the candidate rules are required to match
-     * 
-     * @return  a default-constructed configuration with the appropriate condition set
-     */
-    @Nonnull public static RelyingPartyConfiguration byMappedTag(@Nonnull final Collection<Candidate> candidates,
-            final boolean trim, final boolean matchAll) {
-        Constraint.isNotNull(candidates, "Candidate list cannot be null");
-        
-        // We adapt an OpenSAML Predicate applying to an EntityDescriptor by indirecting the lookup of the
-        // EntityDescriptor to a lookup sequence of PRC -> RPC -> SAMLMetadataContext -> EntityDescriptor.
-        
-        final StrategyIndirectedPredicate<ProfileRequestContext,EntityDescriptor> indirectPredicate =
-                new StrategyIndirectedPredicate<>(
-                        new EntityDescriptorLookupFunction().compose(new SAMLMetadataContextLookupFunction()),
-                        new MappedEntityAttributesPredicate(candidates, trim, matchAll));
-        
-        final DelegatingRelyingPartyConfiguration config = new DelegatingRelyingPartyConfiguration(); 
-        config.setActivationCondition(indirectPredicate);
-
-        return config;
-    }
-
-}
\ No newline at end of file

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


More information about the commits mailing list