[java-identity-provider] branch main updated: IDP-1998 - DynamicAttributePredicate is limited to single value inputs

Scott Cantor cantor.2 at osu.edu
Thu Aug 25 15:29:01 UTC 2022


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

scantor pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=10a3966f8d7b447869b565a75746ba4104a9580b

The following commit(s) were added to refs/heads/main by this push:
     new 10a3966f8 IDP-1998 - DynamicAttributePredicate is limited to single value inputs
10a3966f8 is described below

commit 10a3966f8d7b447869b565a75746ba4104a9580b
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Aug 25 11:26:12 2022 -0400

    IDP-1998 - DynamicAttributePredicate is limited to single value inputs
    
    https://shibboleth.atlassian.net/browse/IDP-1998
---
 .../profile/logic/DynamicAttributePredicate.java   | 41 +++++++--
 .../logic/DynamicAttributePredicateTest.java       | 99 ++++++++++++++++++++++
 2 files changed, 134 insertions(+), 6 deletions(-)

diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicate.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicate.java
index ab6686bc3..0f199dab2 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicate.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicate.java
@@ -45,6 +45,11 @@ import java.util.function.Function;
  * Predicate over an {@link AttributeContext} that derives the value(s) to match based
  * on one or more supplied Functions instead of static values.
  * 
+ * <p>Each function installed must return a value that matches a value of the attribute
+ * corresponding to the map key.</p>
+ * 
+ * <p>Functions may return a {@link String} or a {@link Collection} containing them.</p>
+ * 
  * @since 3.4.0
  */
 public class DynamicAttributePredicate extends AbstractAttributePredicate {
@@ -53,7 +58,7 @@ public class DynamicAttributePredicate extends AbstractAttributePredicate {
     @Nonnull private final Logger log = LoggerFactory.getLogger(DynamicAttributePredicate.class);
 
     /** Map of attribute IDs to functions. */
-    @Nonnull @NonnullElements private ListMultimap<String,Function<ProfileRequestContext,String>> attributeFunctionMap;
+    @Nonnull @NonnullElements private ListMultimap<String,Function<ProfileRequestContext,Object>> attributeFunctionMap;
     
     /** Constructor. */
     public DynamicAttributePredicate() {
@@ -66,11 +71,11 @@ public class DynamicAttributePredicate extends AbstractAttributePredicate {
      * @param map   map of attribute/function pairs
      */
     public void setAttributeFunctionMap(
-            @Nonnull @NonnullElements final Map<String,Collection<Function<ProfileRequestContext,String>>> map) {
+            @Nonnull @NonnullElements final Map<String,Collection<Function<ProfileRequestContext,Object>>> map) {
         Constraint.isNotNull(map, "Attribute/value map cannot be null");
         
         attributeFunctionMap.clear();
-        for (final Map.Entry<String,Collection<Function<ProfileRequestContext,String>>> entry : map.entrySet()) {
+        for (final Map.Entry<String,Collection<Function<ProfileRequestContext,Object>>> entry : map.entrySet()) {
             final String attributeId = StringSupport.trimOrNull(entry.getKey());
             attributeFunctionMap.putAll(attributeId, List.copyOf(entry.getValue()));
         }
@@ -103,6 +108,7 @@ public class DynamicAttributePredicate extends AbstractAttributePredicate {
         return false;
     }
 
+// Checkstyle: CyclomaticComplexity OFF
     /**
      * Implementation of the condition to evaluate.
      * 
@@ -125,9 +131,31 @@ public class DynamicAttributePredicate extends AbstractAttributePredicate {
 
             boolean matched = false;
 
-            for (final Function<ProfileRequestContext,String> fn : attributeFunctionMap.get(id)) {
-                if (findMatch(fn.apply(profileRequestContext), attribute)) {
-                    matched = true;
+            for (final Function<ProfileRequestContext,Object> fn : attributeFunctionMap.get(id)) {
+                
+                final Object candidate = fn.apply(profileRequestContext);
+                
+                if (candidate instanceof String) {
+                    matched = findMatch((String) candidate, attribute);
+                } else if (candidate instanceof Collection<?>) {
+                    for (final Object subcandidate : (Collection<?>) candidate) {
+                        if (subcandidate instanceof String) {
+                            if (findMatch((String) subcandidate, attribute)) {
+                                matched = true;
+                                break;
+                            }
+                        } else {
+                            log.error(
+                                  "Collection returned by function for attribute {} contained an unsupported type: {}",
+                                    id, subcandidate.getClass().getName());
+                        }
+                    }
+                } else {
+                    log.error("Function for attribute {} returned an unsupported type: {}", id,
+                            candidate.getClass().getName());
+                }
+                
+                if (matched) {
                     break;
                 }
             }
@@ -140,6 +168,7 @@ public class DynamicAttributePredicate extends AbstractAttributePredicate {
         
         return true;
     }
+// Checkstyle: CyclomaticComplexity ON
     
     /**
      * Look for a matching value in an attribute.
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicateTest.java b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicateTest.java
new file mode 100644
index 000000000..6a5442ae1
--- /dev/null
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/DynamicAttributePredicateTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.idp.profile.logic;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.testng.Assert.*;
+
+/**
+ * Unit test for {@link DynamicAttributePredicate}.
+ */
+public class DynamicAttributePredicateTest {
+
+    @Test
+    public void testInvalid() {
+        final ProfileRequestContext prc = createProfileRequestContext("foo", List.of("bar", "baz"));
+        DynamicAttributePredicate predicate = new DynamicAttributePredicate();
+        
+        predicate.setAttributeFunctionMap(Map.of("foo", Collections.singleton(FunctionSupport.constant(List.of(10)))));
+        assertFalse(predicate.test(prc));
+
+        predicate.setAttributeFunctionMap(Map.of("foo", Collections.singleton(FunctionSupport.constant(10))));
+        assertFalse(predicate.test(prc));
+    }
+
+    @Test
+    public void testString() {
+        final ProfileRequestContext prc = createProfileRequestContext("foo", List.of("bar", "baz"));
+        DynamicAttributePredicate predicate = new DynamicAttributePredicate();
+        
+        predicate.setAttributeFunctionMap(Map.of("foo2", Collections.singleton(FunctionSupport.constant(List.of("bar")))));
+        assertFalse(predicate.test(prc));
+
+        predicate.setAttributeFunctionMap(Map.of("foo2", Collections.singleton(FunctionSupport.constant("bar"))));
+        assertFalse(predicate.test(prc));
+
+        predicate.setAttributeFunctionMap(Map.of("foo2", Collections.singleton(FunctionSupport.constant("*"))));
+        assertFalse(predicate.test(prc));
+
+        predicate.setAttributeFunctionMap(Map.of("foo", Collections.singleton(FunctionSupport.constant("*"))));
+        assertTrue(predicate.test(prc));
+
+        predicate.setAttributeFunctionMap(Map.of("foo", Collections.singleton(FunctionSupport.constant(List.of("bar", "baz")))));
+        assertTrue(predicate.test(prc));
+    }
+    
+    private ProfileRequestContext createProfileRequestContext(final String name, final Collection<String> values) {
+        final ProfileRequestContext prc = new ProfileRequestContext();
+        final RelyingPartyContext rpc = new RelyingPartyContext();
+        final IdPAttribute attribute = new IdPAttribute(name);
+        final List<IdPAttributeValue> attributeValues = new ArrayList<>();
+        for (final String value : values) {
+            final int i = value.indexOf('@');
+            if (i == -1) {
+                attributeValues.add(new StringAttributeValue(value));
+            } else {
+                attributeValues.add(new ScopedStringAttributeValue(value.substring(0,i), value.substring(i + 1)));
+            }
+        }
+        attribute.setValues(attributeValues);
+        final AttributeContext ac = new AttributeContext();
+        ac.setIdPAttributes(Collections.singletonList(attribute));
+        ac.setUnfilteredIdPAttributes(Collections.singletonList(attribute));
+        rpc.addSubcontext(ac);
+        prc.addSubcontext(rpc);
+        return prc;
+    }
+   
+}
\ 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