[java-plugin-shibd] branch main updated: Flesh out docs and unit tests.

Codeberg noreply at shibboleth.net
Tue Aug 18 16:56:16 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/216fd83b1298424d04e4b41fbe83efc5df84667a

The following commit(s) were added to refs/heads/main by this push:
     new 216fd83  Flesh out docs and unit tests.
216fd83 is described below

commit 216fd83b1298424d04e4b41fbe83efc5df84667a
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Tue Aug 18 12:56:00 2026 -0400

    Flesh out docs and unit tests.
---
 .../credential/impl/CredentialResolverBridge.java  |   7 +-
 .../impl/StaticMapCredentialResolver.java          |  15 +++
 .../sp/credential/impl/MockCredential.java         |  37 +++++-
 .../impl/StaticMapCredentialResolverTest.java      | 127 ++++++++++++++++++++-
 .../sp/credential/impl/staticmapresolver.xml       |  79 ++++++++++++-
 5 files changed, 252 insertions(+), 13 deletions(-)

diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/CredentialResolverBridge.java b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/CredentialResolverBridge.java
index 254a1fb..6c1953e 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/CredentialResolverBridge.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/CredentialResolverBridge.java
@@ -123,14 +123,11 @@ public class CredentialResolverBridge implements CredentialResolver {
         if (arc != null) {
             final Agent agent = arc.getAgent();
             if (agent != null) {
-                final String id = agent.getId();
-                if (id != null) {
-                    finalCriteria.add(new AgentIDCriterion(id));
-                }
+                finalCriteria.add(new AgentIDCriterion(agent));
             }
             final Application app = arc.getApplication();
             if (app != null) {
-                finalCriteria.add(new ApplicationIDCriterion(app.getApplicationId()));
+                finalCriteria.add(new ApplicationIDCriterion(app));
             }
         }
         
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolver.java b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolver.java
index 1ecbfd4..4129d72 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolver.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolver.java
@@ -34,8 +34,11 @@ import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.Criterion;
 import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.sp.Agent;
 import net.shibboleth.sp.AgentIDCriterion;
+import net.shibboleth.sp.Application;
 import net.shibboleth.sp.ApplicationIDCriterion;
 import net.shibboleth.sp.credential.AbstractOrderedCredentialResolver;
 
@@ -47,6 +50,18 @@ import net.shibboleth.sp.credential.AbstractOrderedCredentialResolver;
  * <p>The "exact" matching map is constructed as a nested three-level map, from
  * Agent to Application to RelyingParty and finally to the list of credentials.
  * Each layer uses a null key to signify "any" as a wildcard match.</p>
+ * 
+ * <p>The resolver recognizes these {@link Criterion} types:</p>
+ * 
+ * <ul>
+ *  <li>{@link ProfileRequestContextCriterion} - used only for predicate evaluation</li> 
+ *  <li>{@link AgentIDCriterion} - used for {@link Agent}-indexed rules 
+ *  <li>{@link ApplicationIDCriterion} - used for {@link Application}-based rules 
+ *  <li>{@link EntityIdCriterion} - used for relying party-based rules</li> 
+ * </ul>
+ * 
+ * <p>The absence of a criterion for map-based rules does <strong>not</strong> prevent
+ * rules applying to "any" of an object being applied.</p>
  */
 public class StaticMapCredentialResolver extends AbstractOrderedCredentialResolver {
 
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/MockCredential.java b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/MockCredential.java
index 5d952c8..c4f4712 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/MockCredential.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/MockCredential.java
@@ -27,21 +27,22 @@ import org.opensaml.security.credential.CredentialContextSet;
 import org.opensaml.security.credential.UsageType;
 
 import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
 
 /**
  * Testing class to supply a usable credential type.
  */
 public class MockCredential implements Credential {
 
-    @Nullable private final String entityID; 
+    @Nonnull private final String entityID; 
     
     /**
      * Constructor.
      *
      * @param id entityID for testing
      */
-    public MockCredential(@Nullable final String id) {
-        entityID = id;
+    public MockCredential(@Nonnull final String id) {
+        entityID = Constraint.isNotNull(id, "MockCredential ID cannot be null");
     }
     
     /** {@inheritDoc} */
@@ -84,4 +85,34 @@ public class MockCredential implements Credential {
         return UsageType.UNSPECIFIED;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull public String toString() {
+        return entityID;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return entityID.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof MockCredential) {
+            return entityID.equals(((MockCredential) obj).entityID);
+        }
+
+        return false;
+    }
+    
 }
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolverTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolverTest.java
index 30b535b..fe568a5 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolverTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/StaticMapCredentialResolverTest.java
@@ -20,38 +20,159 @@ import java.util.List;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.sp.AgentIDCriterion;
+import net.shibboleth.sp.ApplicationIDCriterion;
 
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
 import org.opensaml.security.credential.Credential;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
 import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 /**
  * Unit tests for {@link StaticMapCredentialResolver}.
  */
- at SuppressWarnings("javadoc")
 @ContextConfiguration(
         locations = {
                 "/net/shibboleth/sp/credential/impl/staticmapresolver.xml",
                 }
         )
 @Configuration
+ at SuppressWarnings("javadoc")
 public class StaticMapCredentialResolverTest extends AbstractTestNGSpringContextTests {
 
     @Autowired
     @Nonnull private StaticMapCredentialResolver resolver;
+
+    private ProfileRequestContext prc;
+    
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        prc = new WebflowRequestContextProfileRequestContextLookup().apply(new RequestContextBuilder().buildRequestContext());
+    }
     
     @Test public void testPredicates_NoCriteria() throws ResolverException {
         final List<Credential> creds = resolve(null);
-        Assert.assertEquals(creds.size(), 1);
-        Assert.assertEquals(creds.get(0).getEntityId(), "alwaysTrue");
+        
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+
+    @Test public void testPredicates_PRCCriterion() throws ResolverException {
+        final List<Credential> creds = resolve(new CriteriaSet(new ProfileRequestContextCriterion(prc)));
+
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue"),
+                        new MockCredential("nonNull")));
+    }
+    
+    @Test
+    public void testAgent_NoRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("frobnitz"));
+        
+        final List<Credential> creds = resolve(criteria);
+
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
     }
 
+    @Test
+    public void testAgent_WithRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("foo"));
+        
+        final List<Credential> creds = resolve(criteria);
+
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Foo_Any"),
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+    
+    @Test
+    public void testAgentApplication_NoRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("frobnitz"));
+        criteria.add(new ApplicationIDCriterion("frobnitz"));
+        
+        final List<Credential> creds = resolve(criteria);
+        
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+
+    @Test
+    public void testAgentApplication_WithRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("foo"));
+        criteria.add(new ApplicationIDCriterion("zorkmid"));
+        
+        final List<Credential> creds = resolve(criteria);
+        
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Foo_Any"),
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+    
+    @Test
+    public void testAgentApplicationRP_NoRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("frobnitz"));
+        criteria.add(new ApplicationIDCriterion("frobnitz"));
+        criteria.add(new EntityIdCriterion("frobnitz"));
+        
+        final List<Credential> creds = resolve(criteria);
+        
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+    
+    @Test
+    public void testAgentApplicationRP_WithRules() throws ResolverException {
+        final CriteriaSet criteria = new CriteriaSet();
+        criteria.add(new AgentIDCriterion("foo"));
+        criteria.add(new ApplicationIDCriterion("zorkmid"));
+        criteria.add(new EntityIdCriterion("zork1"));
+        
+        final List<Credential> creds = resolve(criteria);
+        
+        Assert.assertEquals(creds,
+                CollectionSupport.listOf(
+                        new MockCredential("Foo_Zork1"),
+                        new MockCredential("Foo_Zork2"),
+                        new MockCredential("Foo_Any"),
+                        new MockCredential("Any_Zork1"),
+                        new MockCredential("Any_Zork2"),
+                        new MockCredential("Any_Any"),
+                        new MockCredential("alwaysTrue")));
+    }
+    
     /**
      * Wraps a resolve call to capture the output into a list for ease of test validation.
      * 
diff --git a/sp-server-impl/src/test/resources/net/shibboleth/sp/credential/impl/staticmapresolver.xml b/sp-server-impl/src/test/resources/net/shibboleth/sp/credential/impl/staticmapresolver.xml
index 31ff725..42eb06b 100644
--- a/sp-server-impl/src/test/resources/net/shibboleth/sp/credential/impl/staticmapresolver.xml
+++ b/sp-server-impl/src/test/resources/net/shibboleth/sp/credential/impl/staticmapresolver.xml
@@ -30,19 +30,94 @@
         class="net.shibboleth.shared.logic.PredicateSupport" factory-method="not" abstract="true" />
     <bean id="shibboleth.Conditions.OR"
         class="net.shibboleth.shared.logic.PredicateSupport" factory-method="or" abstract="true" />
+
+    <bean id="shibboleth.Conditions.Expression"
+        class="net.shibboleth.profile.context.logic.SpringExpressionPredicate" abstract="true" />
     
 
     <bean id="testResolver" class="net.shibboleth.sp.credential.impl.StaticMapCredentialResolver">
     
-        <property name="predicateRules">
+        <!-- Map of agent rules, enclosing map(s) of relying party rules. -->
+        <property name="agentRules">
             <map>
+                <!-- All Agents -->
+                <entry key="#{null}">
+                    <map>
+                        <!-- Any RP. -->
+                        <entry key="#{null}">
+                            <list>
+                                <bean parent="Mock" c:_0="Any_Any" />
+                            </list>
+                        </entry>
+                        
+                        <!-- Specific RPs. -->
+                        <entry key="zork1">
+                            <list>
+                                <bean parent="Mock" c:_0="Any_Zork1" />
+                                <bean parent="Mock" c:_0="Any_Zork2" />
+                            </list>
+                        </entry>
+                        <entry key="zork3">
+                            <list> 
+                                <bean parent="Mock" c:_0="Any_Zork3" />
+                            </list>
+                        </entry>
+                    </map>
+                </entry>
+                
+                <!-- Specific Agents... -->
+                <entry key="foo">
+                    <map>
+                        <!-- Any RP. -->
+                        <entry key="#{null}">
+                            <list>
+                                <bean parent="Mock" c:_0="Foo_Any" />
+                            </list>
+                        </entry>
+                        <!-- Specific RPs. -->
+                        <entry key="zork1">
+                            <list>
+                                <bean parent="Mock" c:_0="Foo_Zork1" />
+                                <bean parent="Mock" c:_0="Foo_Zork2" />
+                            </list>
+                        </entry>
+                        <entry key="zork3">
+                            <list> 
+                                <bean parent="Mock" c:_0="Foo_Zork3" />
+                            </list>
+                        </entry>
+                    </map>
+                </entry>
+
+                <entry key="bar">
+                    <map>
+                        <!-- Any RP. -->
+                        <entry key="#{null}">
+                            <list>
+                                <bean parent="Mock" c:_0="Bar_Any" />
+                            </list>
+                        </entry>
+                    </map>
+                </entry>
+            </map>
+        </property>
+    
+        <property name="predicateRules">
+            <!-- Use a typed map here to control order for tests. -->
+            <util:map map-class="java.util.LinkedHashMap">
                 <entry key-ref="shibboleth.Conditions.TRUE">
                     <bean parent="Mock" c:_0="alwaysTrue" />
                 </entry>
                 <entry key-ref="shibboleth.Conditions.FALSE">
                     <bean parent="Mock" c:_0="alwaysFalse" />
                 </entry>
-            </map>
+                <entry>
+                    <key>
+                        <bean parent="shibboleth.Conditions.Expression" c:_0="#input != null" />
+                    </key>
+                    <bean parent="Mock" c:_0="nonNull" />
+                </entry>
+            </util:map>
         </property>
     </bean>
 

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


More information about the commits mailing list