[java-shib-attribute] 02/02: JSATTR-39 Implement wildcard support in attribute filter

Rod Widdowson rdw at steadingsoftware.com
Thu Apr 17 15:23:19 UTC 2025


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

rdw pushed a commit to branch main
in repository java-shib-attribute.

View the commit online:
http://git.shibboleth.net/view/?p=java-shib-attribute.git;a=commit;h=a033b3b3b5597ed913f5019c85037d436a1b6159

commit a033b3b3b5597ed913f5019c85037d436a1b6159
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Apr 17 16:22:26 2025 +0100

    JSATTR-39 Implement wildcard support in attribute filter
    
    https://shibboleth.atlassian.net/browse/JSATTR-39
    
    Implement default processing with test.
---
 .../filter/context/AttributeFilterContext.java     |  19 +++
 .../attribute/filter/impl/AttributeFilterImpl.java |  22 +++-
 .../filter/impl/AttributeFilterImplTest.java       | 139 +++++++++++++++++++++
 3 files changed, 179 insertions(+), 1 deletion(-)

diff --git a/shib-attribute-filter-api/src/main/java/net/shibboleth/idp/attribute/filter/context/AttributeFilterContext.java b/shib-attribute-filter-api/src/main/java/net/shibboleth/idp/attribute/filter/context/AttributeFilterContext.java
index 3c0ad4c46..ee507a4ed 100644
--- a/shib-attribute-filter-api/src/main/java/net/shibboleth/idp/attribute/filter/context/AttributeFilterContext.java
+++ b/shib-attribute-filter-api/src/main/java/net/shibboleth/idp/attribute/filter/context/AttributeFilterContext.java
@@ -87,6 +87,9 @@ public final class AttributeFilterContext extends BaseContext {
     /** The attribute recipient's group identity. */
     @Nullable private String attributeRecipientGroupID;
 
+    /** Do we include unfiltered attributes into the resolution? */
+    private boolean includeUnfilteredAttributes;
+
     /** Cache of issuer metadata context. */
     @Nullable private SAMLMetadataContext issuerMetadataContext;
     
@@ -154,6 +157,22 @@ public final class AttributeFilterContext extends BaseContext {
         
         return this;
     }
+
+    /**
+     * Will we include unfiltered attributes in the result?
+     * @return whether unfilter attributes are to be included
+     */
+    public boolean isIncludeUnfilteredAttributes() {
+        return includeUnfilteredAttributes;
+    }
+
+    /**
+     * Control whether we will include unfiltered attributes in the result.
+     * @param what if true then we will include unfiltered attributes in the result
+     */
+    public void setIncludeUnfilteredAttributes(boolean what) {
+        includeUnfilteredAttributes = what;
+    }
     
     /**
      * Gets the lookup strategy for locating the profile request context.
diff --git a/shib-attribute-filter-impl/src/main/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImpl.java b/shib-attribute-filter-impl/src/main/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImpl.java
index 05162e5da..2f716f172 100644
--- a/shib-attribute-filter-impl/src/main/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImpl.java
+++ b/shib-attribute-filter-impl/src/main/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImpl.java
@@ -110,7 +110,7 @@ public class AttributeFilterImpl extends AbstractIdentifiableInitializableCompon
             final Map<String, IdPAttribute> prefilteredAttributes = filterContext.getPrefilteredIdPAttributes();
 
             // Create work context to hold intermediate results.
-            filterContext.ensureSubcontext(AttributeFilterWorkContext.class);
+            final AttributeFilterWorkContext workContext = filterContext.ensureSubcontext(AttributeFilterWorkContext.class);
 
             log.debug("{} Beginning process of filtering the following {} attributes: {}", new Object[] {getLogPrefix(),
                     prefilteredAttributes.size(), prefilteredAttributes.keySet(),});
@@ -121,6 +121,26 @@ public class AttributeFilterImpl extends AbstractIdentifiableInitializableCompon
                 policy.apply(filterContext);
             }
 
+            if (filterContext.isIncludeUnfilteredAttributes()) {
+
+                log.debug("{} Including unfiltered attributes (if any)", getLogPrefix());
+                for (final Entry<String, IdPAttribute> entry : filterContext.getPrefilteredIdPAttributes().entrySet()) {
+                    if (workContext.getFilteredAttributeIds().contains(entry.getKey())) {
+                        log.trace("{} Attribute {} has already been considered for filtering", getLogPrefix(), entry.getKey());
+                    } else {
+                        final List<IdPAttributeValue> values = entry.getValue().getValues();
+                        if (values.isEmpty()) {
+                            log.debug("{} Attribute {} had not valuues", getLogPrefix(), entry.getKey());
+                        } else {
+                            log.debug("{} adding {} values for attribute '{}'", getLogPrefix(),
+                                    values.size(), entry.getKey());
+                            log.trace("{} values {} ", getLogPrefix(), values);
+                            workContext.addPermittedIdPAttributeValues(entry.getKey(), values);
+                        }
+                    }
+                }
+            }
+
             for (final Entry<String, IdPAttribute> entry : filterContext.getPrefilteredIdPAttributes().entrySet()) {
                 assert entry!=null;
                 final String key = entry.getKey();
diff --git a/shib-attribute-filter-impl/src/test/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImplTest.java b/shib-attribute-filter-impl/src/test/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImplTest.java
index 4f28b4ae3..1c23a99a7 100644
--- a/shib-attribute-filter-impl/src/test/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImplTest.java
+++ b/shib-attribute-filter-impl/src/test/java/net/shibboleth/idp/attribute/filter/impl/AttributeFilterImplTest.java
@@ -14,6 +14,10 @@
 
 package net.shibboleth.idp.attribute.filter.impl;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
 import java.util.List;
 import java.util.Map;
 
@@ -107,6 +111,141 @@ public class AttributeFilterImplTest {
         }
     }
 
+    @Test public void testIncludeUnfilteredAttributes() throws Exception {
+        final IdPAttribute attribute1 = new IdPAttribute("attribute1");
+        attribute1.setValues(CollectionSupport.listOf(new StringAttributeValue("one"), new StringAttributeValue("two")));
+
+        final IdPAttribute attribute2 = new IdPAttribute("attribute2");
+        attribute2.setValues(CollectionSupport.listOf(new StringAttributeValue("a"), new StringAttributeValue("b")));
+
+        final IdPAttribute attribute3 = new IdPAttribute("attribute3");
+        attribute3.setValues(CollectionSupport.listOf(new StringAttributeValue("un"), new StringAttributeValue("deux")));
+
+        final IdPAttribute attribute4 = new IdPAttribute("attribute4");
+        attribute4.setValues(CollectionSupport.listOf(new StringAttributeValue("ein"), new StringAttributeValue("svo")));
+
+        final List<IdPAttribute> attributes = CollectionSupport.listOf(attribute1, attribute2, attribute3, attribute4);
+
+        //
+        // Always on policy attribute 1 which only releases one value
+        //
+        final MockMatcher attribute1Matcher = new MockMatcher();
+        attribute1Matcher.setMatchingAttribute("attribute1");
+        attribute1Matcher.setMatchingValues(CollectionSupport.singleton(attribute1.getValues().get(0)));
+
+        final AttributeRule attribute1Rule = new AttributeRule();
+        attribute1Rule.setId("attribute1Rule");
+        attribute1Rule.setAttributeId(attribute1.getId());
+        attribute1Rule.setMatcher(attribute1Matcher);
+        attribute1Rule.setIsDenyRule(false);
+        attribute1Rule.initialize();
+
+        final AttributeFilterPolicy policy1 =
+                new AttributeFilterPolicy("attribute1Policy", PolicyRequirementRule.MATCHES_ALL,
+                        CollectionSupport.singletonList(attribute1Rule));
+        policy1.initialize();
+
+        //
+        // Never on policy attribute 2 which would release everything
+        //
+        final MockMatcher attribute2Matcher = new MockMatcher();
+        attribute2Matcher.setMatchingAttribute("attribute2");
+        attribute2Matcher.setMatchingValues(null);
+
+        final AttributeRule attribute2Rule = new AttributeRule();
+        attribute2Rule.setId("attribute2Rule");
+        attribute2Rule.setAttributeId(attribute2.getId());
+        attribute2Rule.setMatcher(attribute2Matcher);
+        attribute2Rule.setIsDenyRule(false);
+        attribute2Rule.initialize();
+
+        final AttributeFilterPolicy policy2 =
+                new AttributeFilterPolicy("attribute2Policy", PolicyRequirementRule.MATCHES_NONE,
+                        CollectionSupport.singletonList(attribute2Rule));
+        policy2.initialize();
+
+        //
+        // Always on policy attribute 3 which denies everything
+        //
+        final MockMatcher attribute3Matcher = new MockMatcher();
+        attribute3Matcher.setMatchingAttribute("attribute3");
+        attribute3Matcher.setMatchingValues(null);
+
+        final AttributeRule attribute3Rule = new AttributeRule();
+        attribute3Rule.setId("attribute3Rule");
+        attribute3Rule.setAttributeId(attribute3.getId());
+        attribute3Rule.setMatcher(attribute3Matcher);
+        attribute3Rule.setIsDenyRule(true);
+        attribute3Rule.initialize();
+
+        final AttributeFilterPolicy policy3 =
+                new AttributeFilterPolicy("attribute3Policy", PolicyRequirementRule.MATCHES_ALL,
+                        CollectionSupport.singletonList(attribute3Rule));
+        policy3.initialize();
+
+        final AttributeFilterImpl engine = new AttributeFilterImpl("engine",
+                CollectionSupport.listOf(policy1, policy2, policy3));
+        engine.initialize();
+
+        //
+        // Try with default behavior
+        //      Attribute1 - filter everything but value "one"
+        //      Attribute2 - policy excludes the attribute
+        //      Attribute3 - rule denies all values
+        //      Attribute4 - not mentioned, so not present
+        //
+        AttributeFilterContext filterContext = new AttributeFilterContext();
+        filterContext.setPrefilteredIdPAttributes(attributes);
+        engine.filterAttributes(filterContext);
+
+        Map<String, IdPAttribute> filteredAttributes = filterContext.getFilteredIdPAttributes();
+        assertEquals(filteredAttributes.size(), 1);
+        IdPAttribute result = filteredAttributes.get(attribute1.getId());
+        assertNotNull(result);
+        List<IdPAttributeValue> values = result.getValues();
+        assertEquals(values.size(), 1);
+        assertEquals(values.get(0).getDisplayValue(), "one");
+
+        //
+        // Now with include unfiltered attributes
+        //
+        filterContext = new AttributeFilterContext();
+        filterContext.setPrefilteredIdPAttributes(attributes);
+        filterContext.setIncludeUnfilteredAttributes(true);
+        //
+        //      Attribute1 - filter everything but value "one"
+        //                   Only this stuff included
+        //      Attribute2 - policy excludes the only attributeRules which mention the attribute
+        //                   So it is included
+        //      Attribute3 - rule denies all values
+        //                   So it is NOT included
+        //      Attribute4 - not mentioned, so not present
+        //                   So it is included
+        engine.filterAttributes(filterContext);
+
+        filteredAttributes = filterContext.getFilteredIdPAttributes();
+        assertEquals(filteredAttributes.size(), 3);
+        result = filteredAttributes.get(attribute1.getId());
+        assertNotNull(result);
+        values = result.getValues();
+        assertEquals(values.size(), 1);
+        assertEquals(values.get(0).getDisplayValue(), "one");
+
+        result = filteredAttributes.get(attribute2.getId());
+        assertNotNull(result);
+        values = result.getValues();
+        assertEquals(values.size(), 2);
+
+        result = filteredAttributes.get(attribute3.getId());
+        assertNull(result);
+
+        result = filteredAttributes.get(attribute4.getId());
+        assertNotNull(result);
+        values = result.getValues();
+        assertEquals(values.size(), 2);
+    }
+
+
     /**
      * Test filtering attributes.
      * 

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


More information about the commits mailing list