First cut at Attribute Policy enforcement.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 18 Dec 2002 23:06:13 +0000 (23:06 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 18 Dec 2002 23:06:13 +0000 (23:06 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@383 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/edu/internet2/middleware/shibboleth/aa/arp/ArpAttribute.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/arp/ArpEngine.java
src/edu/internet2/middleware/shibboleth/aa/arp/ArpTests.java
src/edu/internet2/middleware/shibboleth/aa/arp/Rule.java

diff --git a/src/edu/internet2/middleware/shibboleth/aa/arp/ArpAttribute.java b/src/edu/internet2/middleware/shibboleth/aa/arp/ArpAttribute.java
new file mode 100755 (executable)
index 0000000..75ba633
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+/**
+ * Defines an attribute to which Shibboleth Attribute Release Policies may be applied.
+ *
+ * @author Walter Hoehn (wassa&#064;columbia.edu)
+ */
+public interface ArpAttribute {
+       /**
+        * Returns the name of the Attribute
+        */
+       public String getName();
+
+       /**
+        * Sets the values of the attribute to those represented in an array
+        */
+       public void setValues(Object[] values);
+
+       /**
+        * Returns an array representing the attributes values
+        */
+       public Object[] getValues();
+}
index a6b9ebd..0d7faf7 100755 (executable)
@@ -180,4 +180,94 @@ public class ArpEngine {
                return (URI[]) possibleReleaseSet.toArray(new URI[0]);
        }
 
+       public ArpAttribute[] filterAttributes(
+               ArpAttribute[] attributes,
+               Principal principal,
+               String requester,
+               URL resource)
+               throws ArpProcessingException {
+
+               Set releaseSet = new HashSet();
+
+               //Gather all applicable ARP attribute specifiers
+               Set attributeNames = new HashSet();
+               for (int i = 0; attributes.length > i; i++) {
+                       attributeNames.add(attributes[i].getName());
+               }
+               Rule[] rules = createEffectiveArp(principal, requester, resource).getAllRules();
+               Set applicableRuleAttributes = new HashSet();
+               for (int i = 0; rules.length > i; i++) {
+                       Rule.Attribute[] ruleAttributes = rules[i].getAttributes();
+                       for (int j = 0; ruleAttributes.length > j; j++) {
+                               if (attributeNames.contains(ruleAttributes[j].getName().toString())) {
+                                       applicableRuleAttributes.add(ruleAttributes[j]);
+                               }
+                       }
+               }
+
+               //Canonicalize specifiers
+               Map arpAttributeSpecs =
+                       createCanonicalAttributeSpec(
+                               (Rule.Attribute[]) applicableRuleAttributes.toArray(new Rule.Attribute[0]));
+
+               //Filter
+               for (int i = 0; attributes.length > i; i++) {
+                       Rule.Attribute attribute = (Rule.Attribute) arpAttributeSpecs.get(attributes[i].getName());
+                       
+                       //Handle no specifier
+                       if (attribute == null) {
+                               continue;
+                       }
+                       
+                       //Handle Deny All
+                       if (attribute.denyAnyValue()) {
+                               continue;
+                       }
+
+                       //Handle Permit All
+                       if (attribute.releaseAnyValue() && attribute.getValues().length == 0) {
+                               releaseSet.add(attributes[i]);
+                               continue;
+                       }
+
+                       //Handle Permit All-Except and Permit Specific
+                       Object[] resolvedValues = attributes[i].getValues();
+                       Set releaseValues = new HashSet();
+                       for (int j = 0; resolvedValues.length > j; j++) {
+                               System.err.println(attribute.isValuePermitted(resolvedValues[j]));
+                               if (attribute.isValuePermitted(resolvedValues[j])) {
+                                       releaseValues.add(resolvedValues[j]);
+                               }
+                       }
+                       attributes[i].setValues((ArpAttribute[]) releaseValues.toArray(new ArpAttribute[0]));
+                       releaseSet.add(attributes[i]);
+               }
+               return (ArpAttribute[]) releaseSet.toArray(new ArpAttribute[0]);
+       }
+
+       private Map createCanonicalAttributeSpec(Rule.Attribute[] attributes) {
+               Map canonicalSpec = new HashMap();
+               for (int i = 0; attributes.length > i; i++) {
+                       if (!canonicalSpec.containsKey(attributes[i].getName().toString())) {
+                               canonicalSpec.put(attributes[i].getName().toString(), attributes[i]);
+                       } else {
+                               if (((Rule.Attribute) canonicalSpec.get(attributes[i].getName().toString())).denyAnyValue()) {
+                                       continue;
+                               }
+                               if (attributes[i].denyAnyValue()) {
+                                       ((Rule.Attribute) canonicalSpec.get(attributes[i].getName())).setAnyValueDeny(true);
+                                       continue;
+                               }
+                               if (attributes[i].releaseAnyValue()) {
+                                       ((Rule.Attribute) canonicalSpec.get(attributes[i].getName().toString())).setAnyValuePermit(true);
+                               }
+                               Rule.AttributeValue[] values = attributes[i].getValues();
+                               for (int j = 0; values.length > j; j++) {
+                                       ((Rule.Attribute) canonicalSpec.get(attributes[i].getName().toString())).addValue(values[j]);
+                               }
+                       }
+               }
+               return canonicalSpec;
+       }
+
 }
index 3e7f2f5..3ac9802 100755 (executable)
@@ -438,5 +438,148 @@ public class ArpTests extends TestCase {
                }
 
        }
+       
+       public void testArpApplication() {
+               Properties props = new Properties();
+               props.setProperty(
+                       "edu.internet2.middleware.shibboleth.aa.arp.ArpRepository.implementation",
+                       "edu.internet2.middleware.shibboleth.aa.arp.provider.MemoryArpRepository");
+               ArpRepository repository = null;
+               try {
+                       repository = ArpRepositoryFactory.getInstance(props);
+               } catch (ArpRepositoryException e) {
+                       fail("Failed to create memory-based Arp Repository" + e);
+               }
+               try {
+                       Principal principal1 = new AAPrincipal("TestPrincipal");
+                       URL url1 = new URL("http://www.example.edu/");
+
+                       //Test with just a site ARP
+                       InputStream inStream = new FileInputStream("test/arp1.xml");
+                       DOMParser parser = new DOMParser();
+                       parser.parse(new InputSource(inStream));
+                       Arp arp1 = new Arp();
+                       arp1.marshall(parser.getDocument().getDocumentElement());
+                       repository.update(arp1);
+                       ArpEngine engine = new ArpEngine(repository, props);
+
+                       TestAttribute testAttribute1 =
+                               new TestAttribute(
+                                       "urn:mace:eduPerson:1.0:eduPersonAffiliation",
+                                       new Object[] { "member@example.edu", "faculty@example.edu" });
+                       TestAttribute testAttribute2 =
+                               new TestAttribute(
+                                       "urn:mace:eduPerson:1.0:eduPersonPrincipalName",
+                                       new Object[] { "mehoehn@example.edu" });
+                       ArpAttribute[] releaseAttributes =
+                               engine.filterAttributes(
+                                       new ArpAttribute[] { testAttribute1, testAttribute2 },
+                                       principal1,
+                                       "shar.example.edu",
+                                       url1);
+                       for (int i = 0; releaseAttributes.length > i; i++) {
+                               Object[] values = releaseAttributes[i].getValues();
+                               for (int j = 0; values.length > j; j++) {
+                                       System.err.println(values[j]);
+                               }
+                       }
+                       System.err.println("---");
+                       //Test with site and user ARPs
+                       inStream = new FileInputStream("test/arp7.xml");
+                       parser.parse(new InputSource(inStream));
+                       Arp arp7 = new Arp();
+                       arp7.setPrincipal(principal1);
+                       arp7.marshall(parser.getDocument().getDocumentElement());
+                       repository.update(arp7);
+                       releaseAttributes =
+                               engine.filterAttributes(
+                                       new ArpAttribute[] { testAttribute1, testAttribute2 },
+                                       principal1,
+                                       "shar.example.edu",
+                                       url1);
+                       for (int i = 0; releaseAttributes.length > i; i++) {
+                               Object[] values = releaseAttributes[i].getValues();
+                               for (int j = 0; values.length > j; j++) {
+                                       System.err.println(values[j]);
+                               }
+                       }
+                       System.err.println("---");
+                       releaseAttributes =
+                               engine.filterAttributes(
+                                       new ArpAttribute[] { testAttribute1, testAttribute2 },
+                                       principal1,
+                                       "shar1.example.edu",
+                                       url1);
+                       for (int i = 0; releaseAttributes.length > i; i++) {
+                               Object[] values = releaseAttributes[i].getValues();
+                               for (int j = 0; values.length > j; j++) {
+                                       System.err.println(values[j]);
+                               }
+                       }
+                       System.err.println("---");
+                       inStream = new FileInputStream("test/arp6.xml");
+                       parser.parse(new InputSource(inStream));
+                       Arp arp6 = new Arp();
+                       arp6.setPrincipal(principal1);
+                       arp6.marshall(parser.getDocument().getDocumentElement());
+                       repository.update(arp6);
+                       releaseAttributes =
+                               engine.filterAttributes(
+                                       new ArpAttribute[] { testAttribute1, testAttribute2 },
+                                       principal1,
+                                       "shar.example.edu",
+                                       url1);
+                       for (int i = 0; releaseAttributes.length > i; i++) {
+                               Object[] values = releaseAttributes[i].getValues();
+                               for (int j = 0; values.length > j; j++) {
+                                       System.err.println(values[j]);
+                               }
+                       }
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       fail("Failed to apply ARPs: " + e);
+               }
+       }
+       
+       public class TestAttribute implements ArpAttribute {
+               private String name;
+               private Object[] values;
+
+               public TestAttribute(String name, Object[] values) {
+                       this.name = name;
+                       this.values = values;
+               }
+
+               /**
+                * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#getName()
+                */
+               public String getName() {
+                       return name;
+               }
+
+               /**
+                * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#getValues()
+                */
+               public Object[] getValues() {
+                       return values;
+               }
+
+               /**
+                * @see edu.internet2.middleware.shibboleth.aa.arp.ArpAttribute#setValues(Object[])
+                */
+               public void setValues(Object[] values) {
+                       this.values = values;
+               }
+               
+               public boolean equals(Object object) {
+                       if (!(object instanceof TestAttribute)) {
+                               return false;
+                       }
+                       //finish this
+                       return super.equals(object);
+               }
+
+       }
 
 }
index ee0b004..a3bb8fb 100755 (executable)
@@ -54,6 +54,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
 
 import org.apache.log4j.Logger;
@@ -357,12 +358,88 @@ public class Rule {
                        return false;
                }
                
+               void setAnyValueDeny(boolean b) {
+                       if (b) {
+                       anyValue = true;
+                       anyValueRelease = "deny";
+                       values.clear();
+                       } else {
+                               if (anyValueRelease.equals("deny") && anyValue) {
+                                       anyValue = false;       
+                               }
+                       }
+               }
+               
+               boolean isValuePermitted(Object value) {
+                       //Handle Deny All
+                       if (denyAnyValue()) {
+                               return false;
+                       }
+
+                       //Handle Permit All with no specific values
+                       if (releaseAnyValue() && getValues().length == 0) {
+                               return true;
+                       }
+
+                       //Handle Deny Specific
+                       Iterator iterator = values.iterator();
+                       while (iterator.hasNext()) {
+                               AttributeValue valueSpec = (AttributeValue) iterator.next();
+                               if (valueSpec.getValue().equals(value) && valueSpec.getRelease().equals("deny")) {
+                                       return false;
+                               }
+                       }
+                       //Handle Permit All with no relevant specific denies
+                       if (releaseAnyValue()) {
+                               return true;
+                       }
+
+                       //Handle Permit Specific
+                       iterator = values.iterator();
+                       while (iterator.hasNext()) {
+                               AttributeValue valueSpec = (AttributeValue) iterator.next();
+                               if (valueSpec.getValue().equals(value) && valueSpec.getRelease().equals("permit")) {
+                                       return true;
+                               }
+                       }
+
+                       return false;
+               }
+               
+               void setAnyValuePermit(boolean b) {
+                       if (b) {
+                               anyValue = true;
+                               anyValueRelease = "permit";
+                               Iterator iterator = values.iterator();
+                               while (iterator.hasNext()) {
+                                       AttributeValue value = (AttributeValue) iterator.next();
+                                       if (value.getRelease().equals("permit")) {
+                                               values.remove(value);
+                                       }
+                               }
+                       } else {
+                               if (anyValueRelease.equals("permit") && anyValue) {
+                                       anyValue = false;
+                               }
+                       }
+               }
+               
                URI getName() {
                        return name;    
                }
                AttributeValue[] getValues() {
                        return (AttributeValue[]) values.toArray(new AttributeValue[0]);        
                }
+               
+               void addValue(AttributeValue value) {
+                       if (denyAnyValue()) {
+                               return;
+                       }
+                       if (releaseAnyValue() && value.getRelease().equals("permit")) {
+                               return;
+                       }
+                       values.add(value);      
+               }
 
                void marshall(Element element) throws ArpMarshallingException {
                        //Make sure we are dealing with an Attribute
@@ -394,6 +471,7 @@ public class Rule {
                                }
 
                                //Handle Value definitions
+                               if (!denyAnyValue()) {
                                NodeList valueNodeList = element.getElementsByTagName("Value");
                                for (int i = 0; valueNodeList.getLength() > i; i++) {
                                        String release = null;
@@ -405,9 +483,13 @@ public class Rule {
                                                && ((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);
                                        values.add(aValue);
                                }
+                               }
 
                        }
        }