Added match function testing for attribute values in ARP engine.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 22 Oct 2003 19:01:10 +0000 (19:01 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 22 Oct 2003 19:01:10 +0000 (19:01 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@774 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

data/example12.xml [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/aa/arp/ArpEngine.java
src/edu/internet2/middleware/shibboleth/aa/arp/Rule.java
src/edu/internet2/middleware/shibboleth/aa/arp/provider/StringValueMatchFunction.java [new file with mode: 0644]
tests/edu/internet2/middleware/shibboleth/aa/arp/ArpTests.java

diff --git a/data/example12.xml b/data/example12.xml
new file mode 100644 (file)
index 0000000..ec69f48
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeReleasePolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mace:shibboleth:arp:1.0" xsi:schemaLocation="urn:mace:shibboleth:arp:1.0 shibboleth-arp-1.0.xsd" >
+       <Description>Rule with matching functions set for values.</Description>
+       <Rule>
+               <Target>
+                       <AnyTarget/>
+               </Target>
+               <Attribute name="urn:mace:dir:attribute-def:eduPersonAffiliation">
+                       <AnyValue release="permit"/>
+                       <Value release="deny" matchFunction="urn:mace:shibboleth:arp:matchFunction:regexMatch">^.+@example.edu$</Value>
+               </Attribute>
+               <Attribute name="urn:mace:dir:attribute-def:eduPersonEntitlement">
+                       <Value release="permit" matchFunction="urn:mace:shibboleth:arp:matchFunction:regexMatch">^urn:x:1:.+$</Value>
+               </Attribute>
+       </Rule>
+</AttributeReleasePolicy>
index 9d6ef18..2b7021f 100755 (executable)
@@ -92,6 +92,9 @@ public class ArpEngine {
                        matchFunctions.put(
                                new URI("urn:mace:shibboleth:arp:matchFunction:regexMatch"),
                                "edu.internet2.middleware.shibboleth.aa.arp.provider.RegexMatchFunction");
+                       matchFunctions.put(
+                               new URI("urn:mace:shibboleth:arp:matchFunction:stringValue"),
+                               "edu.internet2.middleware.shibboleth.aa.arp.provider.StringValueMatchFunction");
                } catch (URISyntaxException e) {
                        log.error("Error mapping standard match functions: " + e);
                }
index 735461a..2d4597c 100755 (executable)
@@ -495,6 +495,7 @@ public class Rule {
        }
 
        class Attribute {
+               
                private URI name;
                private boolean anyValue = false;
                private String anyValueRelease = "permit";
@@ -542,10 +543,33 @@ public class Rule {
                        Iterator iterator = values.iterator();
                        while (iterator.hasNext()) {
                                AttributeValue valueSpec = (AttributeValue) iterator.next();
-                               if (valueSpec.getValue().equals(value) && valueSpec.getRelease().equals("deny")) {
+
+                               MatchFunction resourceFunction;
+                               try {
+                                       resourceFunction = ArpEngine.lookupMatchFunction(valueSpec.getMatchFunctionIdentifier());
+                                       // For safety, err on the side of caution
+                                       if (resourceFunction == null) {
+                                               log.warn(
+                                                       "Could not locate matching function for ARP value. Function: "
+                                                               + valueSpec.getMatchFunctionIdentifier().toString());
+                                               return false;
+                                       }
+
+                               } catch (ArpException e) {
+                                       log.error("Error while attempting to find referenced matching function for ARP values: " + e);
+                                       return false;
+                               }
+
+                               try {
+                                       if (valueSpec.getRelease().equals("deny") && resourceFunction.match(valueSpec.getValue(), value)) {
+                                               return false;
+                                       }
+                               } catch (MatchingException e) {
+                                       log.error("Could not apply referenced matching function to ARP value: " + e);
                                        return false;
                                }
                        }
+
                        //Handle Permit All with no relevant specific denies
                        if (releaseAnyValue()) {
                                return true;
@@ -555,11 +579,33 @@ public class Rule {
                        iterator = values.iterator();
                        while (iterator.hasNext()) {
                                AttributeValue valueSpec = (AttributeValue) iterator.next();
-                               if (valueSpec.getValue().equals(value) && valueSpec.getRelease().equals("permit")) {
-                                       return true;
+
+                               MatchFunction resourceFunction;
+                               try {
+                                       resourceFunction = ArpEngine.lookupMatchFunction(valueSpec.getMatchFunctionIdentifier());
+                                       // Ignore non-functional permits
+                                       if (resourceFunction == null) {
+                                               log.warn(
+                                                       "Could not locate matching function for ARP value. Function: "
+                                                               + valueSpec.getMatchFunctionIdentifier().toString());
+                                               continue;
+                                       }
+
+                               } catch (ArpException e) {
+                                       log.error("Error while attempting to find referenced matching function for ARP values: " + e);
+                                       continue;
                                }
-                       }
 
+                               try {
+                                       if (valueSpec.getRelease().equals("permit")
+                                               && resourceFunction.match(valueSpec.getValue(), value)) {
+                                               return true;
+                                       }
+                               } catch (MatchingException e) {
+                                       log.error("Could not apply referenced matching function to ARP value: " + e);
+                                       continue;
+                               }
+                       }
                        return false;
                }
 
@@ -608,22 +654,17 @@ public class Rule {
                Element unmarshall() throws ArpMarshallingException {
 
                        try {
-                               Document placeHolder =
-                                       DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+                               Document placeHolder = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
                                Element attributeNode = placeHolder.createElementNS(Arp.arpNamespace, "Attribute");
 
                                attributeNode.setAttributeNS(Arp.arpNamespace, "name", name.toString());
 
                                if (identifier != null) {
-                                       attributeNode.setAttributeNS(
-                                               Arp.arpNamespace,
-                                               "identifier",
-                                               identifier.toString());
+                                       attributeNode.setAttributeNS(Arp.arpNamespace, "identifier", identifier.toString());
                                }
 
                                if (anyValue) {
-                                       Element anyValueNode =
-                                               placeHolder.createElementNS(Arp.arpNamespace, "AnyValue");
+                                       Element anyValueNode = placeHolder.createElementNS(Arp.arpNamespace, "AnyValue");
                                        anyValueNode.setAttributeNS(Arp.arpNamespace, "release", anyValueRelease);
                                        attributeNode.appendChild(anyValueNode);
                                }
@@ -632,12 +673,23 @@ public class Rule {
                                        AttributeValue value = (AttributeValue) valueIterator.next();
                                        Element valueNode = placeHolder.createElementNS(Arp.arpNamespace, "Value");
                                        valueNode.setAttributeNS(Arp.arpNamespace, "release", value.getRelease());
+                                       if (!value
+                                               .getMatchFunctionIdentifier()
+                                               .equals(new URI("urn:mace:shibboleth:arp:matchFunction:stringValue"))) {
+                                               valueNode.setAttributeNS(
+                                                       Arp.arpNamespace,
+                                                       "matchFunction",
+                                                       value.getMatchFunctionIdentifier().toString());
+                                       }
                                        Text valueTextNode = placeHolder.createTextNode(value.getValue());
                                        valueNode.appendChild(valueTextNode);
                                        attributeNode.appendChild(valueNode);
                                }
                                return attributeNode;
 
+                       } catch (URISyntaxException e) {
+                               log.error("Encountered a problem unmarshalling an ARP Rule Resource: " + e);
+                               throw new ArpMarshallingException("Encountered a problem unmarshalling an ARP Rule Resource.");
                        } catch (ParserConfigurationException e) {
                                log.error("Encountered a problem unmarshalling an ARP Rule: " + e);
                                throw new ArpMarshallingException("Encountered a problem unmarshalling an ARP Rule.");
@@ -679,8 +731,7 @@ public class Rule {
                        }
 
                        //Handle <AnyValue/> definitions
-                       NodeList anyValueNodeList =
-                               element.getElementsByTagNameNS(Arp.arpNamespace, "AnyValue");
+                       NodeList anyValueNodeList = element.getElementsByTagNameNS(Arp.arpNamespace, "AnyValue");
                        if (anyValueNodeList.getLength() == 1) {
                                anyValue = true;
                                if (((Element) anyValueNodeList.item(0)).hasAttribute("release")) {
@@ -694,20 +745,32 @@ public class Rule {
                                for (int i = 0; valueNodeList.getLength() > i; i++) {
                                        String release = null;
                                        String value = null;
+                                       URI matchFunctionIdentifier = null;
                                        if (((Element) valueNodeList.item(i)).hasAttribute("release")) {
                                                release = ((Element) valueNodeList.item(i)).getAttribute("release");
                                        }
+
+                                       //Grab the match function
+                                       try {
+                                               if (((Element) valueNodeList.item(i)).hasAttribute("matchFunction")) {
+                                                       matchFunctionIdentifier =
+                                                               new URI(((Element) valueNodeList.item(i)).getAttribute("matchFunction"));
+                                               }
+                                       } catch (URISyntaxException e) {
+                                               log.error(
+                                                       "ARP match function not identified by a proper URI: "
+                                                               + ((Element) valueNodeList.item(i)).getAttribute("matchFunction"));
+                                               throw new ArpMarshallingException("ARP match function not identified by a proper URI.");
+                                       }
+
                                        if (((Element) valueNodeList.item(i)).hasChildNodes()
-                                               && ((Element) valueNodeList.item(i)).getFirstChild().getNodeType()
-                                                       == Node.TEXT_NODE) {
-                                               value =
-                                                       ((CharacterData) ((Element) valueNodeList.item(i)).getFirstChild())
-                                                               .getData();
+                                               && ((Element) valueNodeList.item(i)).getFirstChild().getNodeType() == Node.TEXT_NODE) {
+                                               value = ((CharacterData) ((Element) valueNodeList.item(i)).getFirstChild()).getData();
                                        }
                                        if (releaseAnyValue() && release.equals("permit")) {
                                                continue;
                                        }
-                                       AttributeValue aValue = new AttributeValue(release, value);
+                                       AttributeValue aValue = new AttributeValue(release, matchFunctionIdentifier, value);
                                        values.add(aValue);
                                }
                        }
@@ -715,12 +778,23 @@ public class Rule {
                }
        }
        class AttributeValue {
+
                private String release = "permit";
                private String value;
+               private URI matchFunctionIdentifier;
 
-               AttributeValue(String release, String value) {
+               AttributeValue(String release, URI matchFunctionIdentifier, String value) throws ArpMarshallingException {
                        setRelease(release);
                        this.value = value;
+                       if (matchFunctionIdentifier != null) {
+                               this.matchFunctionIdentifier = matchFunctionIdentifier;
+                       } else {
+                               try {
+                                       matchFunctionIdentifier = new URI("urn:mace:shibboleth:arp:matchFunction:stringValue");
+                               } catch (URISyntaxException e) {
+                                       throw new ArpMarshallingException("ARP Engine internal error: could not set default matching function for attribute value.");
+                               }
+                       }
                }
 
                String getRelease() {
@@ -731,6 +805,10 @@ public class Rule {
                        return value;
                }
 
+               URI getMatchFunctionIdentifier() {
+                       return matchFunctionIdentifier;
+               }
+
                void setRelease(String release) {
                        if (release == null) {
                                return;
diff --git a/src/edu/internet2/middleware/shibboleth/aa/arp/provider/StringValueMatchFunction.java b/src/edu/internet2/middleware/shibboleth/aa/arp/provider/StringValueMatchFunction.java
new file mode 100644 (file)
index 0000000..f34e2f4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * The Shibboleth License, Version 1.
+ * Copyright (c) 2002
+ * University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution, if any, must include
+ * the following acknowledgment: "This product includes software developed by
+ * the University Corporation for Advanced Internet Development
+ * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
+ * may appear in the software itself, if and wherever such third-party
+ * acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor
+ * Internet2, nor the University Corporation for Advanced Internet Development,
+ * Inc., nor UCAID may be used to endorse or promote products derived from this
+ * software without specific prior written permission. For written permission,
+ * please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2,
+ * UCAID, or the University Corporation for Advanced Internet Development, nor
+ * may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
+ * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.aa.arp.provider;
+
+import org.apache.log4j.Logger;
+
+import edu.internet2.middleware.shibboleth.aa.arp.MatchFunction;
+import edu.internet2.middleware.shibboleth.aa.arp.MatchingException;
+
+/**
+ * Match function that does exact string matching.
+ *
+ * @author Walter Hoehn (wassa&#064;columbia.edu)
+ */
+public class StringValueMatchFunction implements MatchFunction {
+       private static Logger log = Logger.getLogger(StringValueMatchFunction.class.getName());
+       /**
+        * @see edu.internet2.middleware.shibboleth.aa.arp.MatchFunction#match(Object,
+        *              Object)
+        */
+       public boolean match(Object arpComponent, Object requestComponent)
+               throws MatchingException
+       {
+               if (!(arpComponent instanceof String) || !(requestComponent instanceof String)) {
+                       log.error("Invalid use of ARP matching function (StringValueMatchFunction).");
+                       throw new MatchingException("Invalid use of ARP matching function (StringValueMatchFunction).");
+               }
+               return arpComponent.equals(requestComponent);
+       }
+}
index 9039f19..46da1e5 100755 (executable)
@@ -103,7 +103,8 @@ public class ArpTests extends TestCase {
                        "data/example8.xml",
                        "data/example9.xml",
                        "data/example10.xml",
-                       "data/example11.xml" };
+                       "data/example11.xml",
+                       "data/example12.xml" };
 
        public ArpTests(String name) {
                super(name);
@@ -607,6 +608,8 @@ public class ArpTests extends TestCase {
                        arpApplicationTest19(repository, props, parser);
                        arpApplicationTest20(repository, props, parser);
                        arpApplicationTest21(repository, props, parser);
+                       arpApplicationTest22(repository, props, parser);
+                       arpApplicationTest23(repository, props, parser);
 
                } catch (Exception e) {
                        e.printStackTrace();
@@ -1853,5 +1856,100 @@ public class ArpTests extends TestCase {
 
                assertEquals("ARP application test 21: ARP not applied as expected.", inputSet, releaseSet);
        }
+       /**
+        * ARPs: A site ARP only
+        * Target: Specific shar, Specific resource
+        * Attribute: Release values by regex
+        */
+       void arpApplicationTest22(ArpRepository repository, Properties props, DOMParser parser) throws Exception {
+
+               //Gather the Input
+               String rawArp =
+                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+                               + "<AttributeReleasePolicy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mace:shibboleth:arp:1.0\" xsi:schemaLocation=\"urn:mace:shibboleth:arp:1.0 shibboleth-arp-1.0.xsd\">"
+                               + "                     <Rule>"
+                               + "                             <Target>"
+                               + "                                     <Requester>shar.example.edu</Requester>"
+                               + "                                     <Resource>http://www.example.edu/</Resource>"
+                               + "                             </Target>"
+                               + "                             <Attribute name=\"urn:mace:dir:attribute-def:eduPersonEntitlement\">"
+                               + "                                     <Value release=\"permit\" matchFunction=\"urn:mace:shibboleth:arp:matchFunction:regexMatch\">^urn:x:a.+$</Value>"
+                               + "                             </Attribute>"
+                               + "                     </Rule>"
+                               + "     </AttributeReleasePolicy>";
+
+               Principal principal1 = new AuthNPrincipal("Test2Principal");
+               URL url1 = new URL("http://www.example.edu/index.html");
+               AAAttributeSet inputSet =
+                       new AAAttributeSet(
+                               new AAAttribute(
+                                       "urn:mace:dir:attribute-def:eduPersonEntitlement",
+                                       new Object[] { "urn:x:a", "urn:x:foo", "urn:x:bar", "urn:x:adagio", "urn:x:awol" }));
+               AAAttributeSet releaseSet =
+                       new AAAttributeSet(
+                               new AAAttribute(
+                                       "urn:mace:dir:attribute-def:eduPersonEntitlement",
+                                       new Object[] { "urn:x:adagio", "urn:x:awol" }));
+
+               //Setup the engine
+               parser.parse(new InputSource(new StringReader(rawArp)));
+               Arp siteArp = new Arp();
+               siteArp.marshall(parser.getDocument().getDocumentElement());
+               repository.update(siteArp);
+               ArpEngine engine = new ArpEngine(repository, props);
+
+               //Apply the ARP
+               engine.filterAttributes(inputSet, principal1, "shar.example.edu", url1);
+
+               assertEquals("ARP application test 22: ARP not applied as expected.", inputSet, releaseSet);
+       }
+       /**
+        * ARPs: A site ARP only
+        * Target: Specific shar, Specific resource
+        * Attribute: Deny specific values by regex
+        */
+       void arpApplicationTest23(ArpRepository repository, Properties props, DOMParser parser) throws Exception {
+
+               //Gather the Input
+               String rawArp =
+                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+                               + "<AttributeReleasePolicy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mace:shibboleth:arp:1.0\" xsi:schemaLocation=\"urn:mace:shibboleth:arp:1.0 shibboleth-arp-1.0.xsd\">"
+                               + "                     <Rule>"
+                               + "                             <Target>"
+                               + "                                     <Requester>shar.example.edu</Requester>"
+                               + "                                     <Resource>http://www.example.edu/</Resource>"
+                               + "                             </Target>"
+                               + "                             <Attribute name=\"urn:mace:dir:attribute-def:eduPersonEntitlement\">"
+                               + "                                     <AnyValue release=\"permit\" />"
+                               + "                                     <Value release=\"deny\" matchFunction=\"urn:mace:shibboleth:arp:matchFunction:regexMatch\">^urn:x:a.+$</Value>"
+                               + "                             </Attribute>"
+                               + "                     </Rule>"
+                               + "     </AttributeReleasePolicy>";
+
+               Principal principal1 = new AuthNPrincipal("Test2Principal");
+               URL url1 = new URL("http://www.example.edu/index.html");
+               AAAttributeSet inputSet =
+                       new AAAttributeSet(
+                               new AAAttribute(
+                                       "urn:mace:dir:attribute-def:eduPersonEntitlement",
+                                       new Object[] { "urn:x:a", "urn:x:foo", "urn:x:bar", "urn:x:adagio", "urn:x:awol" }));
+               AAAttributeSet releaseSet =
+                       new AAAttributeSet(
+                               new AAAttribute(
+                                       "urn:mace:dir:attribute-def:eduPersonEntitlement",
+                                       new Object[] { "urn:x:a", "urn:x:foo", "urn:x:bar" }));
+
+               //Setup the engine
+               parser.parse(new InputSource(new StringReader(rawArp)));
+               Arp siteArp = new Arp();
+               siteArp.marshall(parser.getDocument().getDocumentElement());
+               repository.update(siteArp);
+               ArpEngine engine = new ArpEngine(repository, props);
+
+               //Apply the ARP
+               engine.filterAttributes(inputSet, principal1, "shar.example.edu", url1);
+
+               assertEquals("ARP application test 23: ARP not applied as expected.", inputSet, releaseSet);
+       }
 
 }