[java-identity-provider] branch master updated: Extend attribute mapping and mapped predicate to EntitiesDescriptors.

Scott Cantor cantor.2 at osu.edu
Mon May 20 19:07:35 EDT 2019


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

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

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

The following commit(s) were added to refs/heads/master by this push:
       new  4211594   Extend attribute mapping and mapped predicate to EntitiesDescriptors.
4211594 is described below

commit 4211594238859df0173eedf1c70c599d4627e0b5
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon May 20 19:07:29 2019 -0400

    Extend attribute mapping and mapped predicate to EntitiesDescriptors.
---
 .../logic/MappedEntityAttributesPredicate.java     | 73 +++++++++++++++-------
 .../impl/AttributeMappingNodeProcessor.java        | 24 ++++---
 .../impl/EntityAttributesPredicateTest.java        | 34 ++++++++++
 .../impl/metadata/attribute-mapping-metadata.xml   | 13 ++--
 .../shibboleth/idp/saml/impl/metadata/rules/rs.txt |  3 -
 5 files changed, 109 insertions(+), 38 deletions(-)

diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/MappedEntityAttributesPredicate.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/MappedEntityAttributesPredicate.java
index f091832..0882daf 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/MappedEntityAttributesPredicate.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/profile/logic/MappedEntityAttributesPredicate.java
@@ -17,6 +17,7 @@
 
 package net.shibboleth.idp.saml.profile.logic;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -24,7 +25,9 @@ import java.util.regex.Pattern;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.profile.logic.EntityAttributesPredicate;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,7 +71,7 @@ public class MappedEntityAttributesPredicate extends EntityAttributesPredicate {
         super(candidates);
 
         Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
-                "Use of nameFormat property is impermissible for MappedEntityAttributesPredicate");
+                "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
     }
 
     /**
@@ -83,7 +86,7 @@ public class MappedEntityAttributesPredicate extends EntityAttributesPredicate {
         super(candidates, trim);
         
         Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
-                "Use of nameFormat property is impermissible for MappedEntityAttributesPredicate");
+                "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
     }
     
     /**
@@ -100,7 +103,7 @@ public class MappedEntityAttributesPredicate extends EntityAttributesPredicate {
         super(candidates, trim, all);
         
         Constraint.isTrue(Iterables.all(candidates, c -> c.getNameFormat() == null),
-                "Use of nameFormat property is impermissible for MappedEntityAttributesPredicate");
+                "Use of nameFormat property is impermissible with MappedEntityAttributesPredicate");
     }
     
     /**
@@ -119,38 +122,64 @@ public class MappedEntityAttributesPredicate extends EntityAttributesPredicate {
     @Override
     public boolean test(@Nullable final EntityDescriptor input) {
         
-        if (input == null) {
-            return false;
+        if (input == null || getCandidates().isEmpty()) {
+            return true;
         }
+        
+        final Collection<Candidate> candidates = new ArrayList<>(getCandidates());
 
+        if (doTest(input, input.getEntityID(), candidates)) {
+            
+            // At least one match. Check if sufficient.
+            if (!getMatchAll() || candidates.isEmpty()) {
+                return true;
+            }
+        }
+        
+        XMLObject parent = input.getParent();
+        while (parent instanceof EntitiesDescriptor) {
+            if (doTest(parent, ((EntitiesDescriptor) parent).getName(), candidates)) {
+                
+                // At least one match. Check if sufficient.
+                if (!getMatchAll() || candidates.isEmpty()) {
+                    return true;
+                }
+            }
+            parent = parent.getParent();
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Evaluate the input object's attached object metadata against the supplied candidates.
+     * 
+     * <p>Any candidates that match will be removed from the input collection.</p>
+     * 
+     * @param input input object
+     * @param name label for logging
+     * @param candidates candidates to check
+     * 
+     * @return true iff the attached object metadata matched at least one input candidate
+     */
+    private boolean doTest(@Nullable final XMLObject input, @Nullable final String name,
+            @Nonnull @NonnullElements final Collection<Candidate> candidates) {
         final List<AttributesMapContainer> containerList =
                 input.getObjectMetadata().get(AttributesMapContainer.class);
         if (null == containerList || containerList.isEmpty() || containerList.get(0).get() == null ||
                 containerList.get(0).get().isEmpty()) {
-            log.trace("No mapped Entity Attributes for {}", input.getEntityID());
+            log.trace("No mapped Entity Attributes for {}", name);
             return false;
         }
         
         final Multimap<String,? extends IdPAttribute> entityAttributes = containerList.get(0).get();
         
         log.trace("Checking for match against {} Entity Attributes for {}", entityAttributes.size(),
-                input.getEntityID());
-        
-        // If we find a matching tag, we win. Each tag is treated in OR fashion.
-        final EntityAttributesMatcher matcher = new EntityAttributesMatcher(entityAttributes);
+                name);
         
-        // Then we determine whether the overall set of tag containers is AND or OR.
-        if (getMatchAll()) {
-            if (Iterables.all(getCandidates(), matcher::test)) {
-                return true;
-            }
-        } else {
-            if (Iterables.tryFind(getCandidates(), matcher::test).isPresent()) {
-                return true;
-            }
-        }
-        
-        return false;
+        // Remove each candidate that matches. Tag values are OR'd for matching purposes.
+        // Return true iff at least one candidate matches.
+        return candidates.removeIf(new EntityAttributesMatcher(entityAttributes));
     }
 
     /**
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/AttributeMappingNodeProcessor.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/AttributeMappingNodeProcessor.java
index 14e8581..d949eeb 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/AttributeMappingNodeProcessor.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/metadata/impl/AttributeMappingNodeProcessor.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.NotThreadSafe;
 
 import net.shibboleth.idp.attribute.AttributeDecodingException;
@@ -50,6 +51,7 @@ import org.opensaml.saml.metadata.resolver.filter.FilterException;
 import org.opensaml.saml.metadata.resolver.filter.MetadataNodeProcessor;
 import org.opensaml.saml.saml2.core.Attribute;
 import org.opensaml.saml.saml2.metadata.AttributeConsumingService;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
 import org.opensaml.saml.saml2.metadata.Extensions;
 import org.opensaml.saml.saml2.metadata.RequestedAttribute;
@@ -109,7 +111,12 @@ public class AttributeMappingNodeProcessor implements MetadataNodeProcessor {
                 if (component == null) {
                     log.error("Attribute transcoding service unavailable");
                 } else {
-                    handleEntityDescriptor(component.getComponent(), (EntityDescriptor) metadataNode);
+                    handleEntityAttributes(component.getComponent(), ((EntityDescriptor) metadataNode).getExtensions());
+                    XMLObject parent = metadataNode.getParent();
+                    while (parent instanceof EntitiesDescriptor) {
+                        handleEntityAttributes(component.getComponent(), ((EntitiesDescriptor) parent).getExtensions());
+                        parent = parent.getParent();
+                    }
                 }
             }
         } finally {
@@ -148,15 +155,14 @@ public class AttributeMappingNodeProcessor implements MetadataNodeProcessor {
     }
 
     /**
-     * Look inside the {@link EntityDescriptor} for entities Attributes and map them.
+     * Look inside the {@link Extensions} for {@link EntityAttributes) and map them.
      * 
      * @param registry the registry service
-     * @param entity the entity
+     * @param extensions the extensions block
      */
-//CheckStyle: CyclomaticComplexity|ReturnCount OFF
-    private void handleEntityDescriptor(@Nonnull final AttributeTranscoderRegistry registry,
-            @Nonnull final EntityDescriptor entity) {
-        final Extensions extensions = entity.getExtensions();
+//CheckStyle: CyclomaticComplexity OFF
+    private void handleEntityAttributes(@Nonnull final AttributeTranscoderRegistry registry,
+            @Nullable final Extensions extensions) {
         if (null == extensions) {
             return;
         }
@@ -195,10 +201,10 @@ public class AttributeMappingNodeProcessor implements MetadataNodeProcessor {
         }
         
         if (!results.isEmpty()) {
-            entity.getObjectMetadata().put(new AttributesMapContainer<>(results));
+            extensions.getParent().getObjectMetadata().put(new AttributesMapContainer<>(results));
         }
     }
-  //CheckStyle: CyclomaticComplexity|ReturnCount ON
+  //CheckStyle: CyclomaticComplexity ON
 
     /**
      * Access the registry of transcoding rules to decode the input object.
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/metadata/impl/EntityAttributesPredicateTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/metadata/impl/EntityAttributesPredicateTest.java
index 090d43b..24f9b65 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/metadata/impl/EntityAttributesPredicateTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/metadata/impl/EntityAttributesPredicateTest.java
@@ -58,6 +58,8 @@ public class EntityAttributesPredicateTest extends XMLObjectBaseTestCase {
     
     private String barEntityID = "http://bar.example.org/shibboleth";
     
+    private String bazEntityID = "http://baz.example.org/shibboleth";
+    
     private GenericApplicationContext pendingTeardownContext = null;
     
     private MetadataResolver resolver = null;
@@ -129,9 +131,25 @@ public class EntityAttributesPredicateTest extends XMLObjectBaseTestCase {
         final EntityAttributesPredicate predicate = new EntityAttributesPredicate(Collections.singletonList(tag));
         Assert.assertFalse(predicate.test(getEntity(fooEntityID)));
         Assert.assertTrue(predicate.test(getEntity(barEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
     }    
     
     @Test
+    public void testMultiLevelMatch() throws ResolverException {
+        final Candidate tag1 = new Candidate("http://macedir.org/entity-category", Attribute.URI_REFERENCE);
+        tag1.setValues(Collections.singletonList("http://refeds.org/category/research-and-scholarship"));
+
+        final Candidate tag2 = new Candidate("urn:oasis:names:tc:SAML:profiles:subject-id:req", Attribute.URI_REFERENCE);
+        tag2.setValues(Collections.singletonList("none"));
+
+        final EntityAttributesPredicate predicate =
+                new EntityAttributesPredicate(Arrays.asList(tag1, tag2), false, true);
+        Assert.assertTrue(predicate.test(getEntity(fooEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(barEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+    }
+    
+    @Test
     public void testSimpleMatchMapped() throws ResolverException {
         
         final Candidate tag = new Candidate("zorkmids");
@@ -140,6 +158,22 @@ public class EntityAttributesPredicateTest extends XMLObjectBaseTestCase {
         final MappedEntityAttributesPredicate predicate = new MappedEntityAttributesPredicate(Collections.singletonList(tag));
         Assert.assertFalse(predicate.test(getEntity(fooEntityID)));
         Assert.assertTrue(predicate.test(getEntity(barEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
+    }
+
+    @Test
+    public void testMultiLevelMappedMatch() throws ResolverException {
+        final Candidate tag1 = new Candidate("http://macedir.org/entity-category");
+        tag1.setValues(Collections.singletonList("http://refeds.org/category/research-and-scholarship"));
+
+        final Candidate tag2 = new Candidate("subject-id-req");
+        tag2.setValues(Collections.singletonList("none"));
+
+        final MappedEntityAttributesPredicate predicate =
+                new MappedEntityAttributesPredicate(Arrays.asList(tag1, tag2), false, true);
+        Assert.assertTrue(predicate.test(getEntity(fooEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(barEntityID)));
+        Assert.assertFalse(predicate.test(getEntity(bazEntityID)));
     }
 
 }
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/attribute-mapping-metadata.xml b/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/attribute-mapping-metadata.xml
index 6a5077a..a9850f5 100644
--- a/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/attribute-mapping-metadata.xml
+++ b/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/attribute-mapping-metadata.xml
@@ -3,15 +3,20 @@
     xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
     xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
     xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute">
-   
-   <EntityDescriptor entityID="http://foo.example.org/shibboleth">
-      
-      <Extensions>
+    
+    <Extensions>
         <mdattr:EntityAttributes>
             <saml:Attribute Name="http://macedir.org/entity-category"
                 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                 <saml:AttributeValue>http://refeds.org/category/research-and-scholarship</saml:AttributeValue>
             </saml:Attribute>
+        </mdattr:EntityAttributes>
+    </Extensions>
+   
+    <EntityDescriptor entityID="http://foo.example.org/shibboleth">
+      
+      <Extensions>
+        <mdattr:EntityAttributes>
             <saml:Attribute Name="urn:oasis:names:tc:SAML:profiles:subject-id:req"
                 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
                 <saml:AttributeValue>none</saml:AttributeValue>
diff --git a/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/rules/rs.txt b/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/rules/rs.txt
deleted file mode 100644
index 12d0bc8..0000000
--- a/idp-saml-impl/src/test/resources/net/shibboleth/idp/saml/impl/metadata/rules/rs.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-id = rands
-transcoderBean = SAML2StringTranscoder
-name = http://macedir.org/entity-category

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


More information about the commits mailing list