Initail Version
authordousti <dousti@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 7 Jun 2002 20:34:40 +0000 (20:34 +0000)
committerdousti <dousti@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 7 Jun 2002 20:34:40 +0000 (20:34 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@41 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

22 files changed:
src/edu/internet2/middleware/shibboleth/aa/AAAttributes.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AAException.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AAPermissionException.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AAResponder.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AASaml.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AAServlet.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AA_Acl.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AA_AclEntry.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AA_Identity.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/AA_Permission.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/Arp.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpAttribute.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpCore.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpFactory.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpFileFactory.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpFilter.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpFilterValue.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpRepository.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpResource.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/ArpShar.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/TName.java [new file with mode: 0755]
src/edu/internet2/middleware/shibboleth/aa/makefile [new file with mode: 0755]

diff --git a/src/edu/internet2/middleware/shibboleth/aa/AAAttributes.java b/src/edu/internet2/middleware/shibboleth/aa/AAAttributes.java
new file mode 100755 (executable)
index 0000000..06a3913
--- /dev/null
@@ -0,0 +1,56 @@
+package aa;
+
+//import aa.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+import java.util.jar.*;
+
+/**
+ * A class for managing local attributes
+ */
+public class AAAttributes{
+
+    Class[] attrClasses = new Class[1];
+
+    /**
+     * Sole constructor. Takes a directory name in the local file system
+     * where attribute classes reside
+     */
+
+    public AAAttributes(String jarFileName)
+       throws AAException{
+
+       try{
+
+           JarFile jf = new JarFile(jarFileName);
+           Vector attrs = new Vector();
+           Enumeration en = jf.entries();
+           while(en.hasMoreElements()){
+               JarEntry je = (JarEntry)en.nextElement();
+               String filename = (String)je.getName();
+               if(filename.endsWith(".class")){
+                   String name = filename.substring(0, filename.lastIndexOf(".class"));
+                   Class attr = Class.forName(name);
+                   attrs.add(attr);
+               }
+           }
+           attrClasses = (Class[])attrs.toArray(attrClasses);
+       }catch(Exception e){
+           throw new AAException("Failed to get the list of attribute classes: "+e);
+       }
+    }
+
+
+    public Class[] listClasses(){
+       return attrClasses;
+    }
+
+    public String[] list(){
+       String[] a = new String[attrClasses.length];
+       for(int i=0; i<a.length; i++){
+           a[i] = attrClasses[i].getName();
+       }
+       return a;
+    }
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AAException.java b/src/edu/internet2/middleware/shibboleth/aa/AAException.java
new file mode 100755 (executable)
index 0000000..766a960
--- /dev/null
@@ -0,0 +1,11 @@
+package aa;
+
+public class AAException extends Exception{
+    String msg;
+    public AAException(String s){
+       msg = s;
+    }
+    public String toString(){
+       return msg;
+    }
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AAPermissionException.java b/src/edu/internet2/middleware/shibboleth/aa/AAPermissionException.java
new file mode 100755 (executable)
index 0000000..2aea0ba
--- /dev/null
@@ -0,0 +1,11 @@
+package aa;
+
+public class AAPermissionException extends Exception{
+    String msg;
+    AAPermissionException(String s){
+       msg = s;
+    }
+    public String toString(){
+       return msg;
+    }
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AAResponder.java b/src/edu/internet2/middleware/shibboleth/aa/AAResponder.java
new file mode 100755 (executable)
index 0000000..e6b3ec2
--- /dev/null
@@ -0,0 +1,239 @@
+package aa;
+
+//import aa.*;
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import edu.internet2.middleware.shibboleth.*;
+import edu.internet2.middleware.eduPerson.*;
+import org.w3c.dom.*;
+import org.opensaml.*;
+
+public class AAResponder{
+
+    //HandleRepositoryFactory hrf;
+    ArpFactory arpFactory;
+    Arp adminArp;
+    DirContext ctx;
+    String domain;
+
+    public AAResponder(/*HandleRepositoryFactory*/String hrf, ArpFactory arpFactory, DirContext ctx, String domain)
+       throws AAException{
+
+       //this.hrf = hrf;
+       this.arpFactory = arpFactory;
+       adminArp = arpFactory.getInstance("admin", true);
+       if(adminArp.isNew())
+           throw new AAException("Admin Arp not found! ");
+       this.ctx = ctx;
+       this.domain = domain;
+    }
+
+
+    public SAMLAttribute[] getReleaseAttributes(String uidSyntax, String handle, String sharName, String url)
+       throws AAException/*,HandleException*/ {
+
+       DirContext userCtx = null;
+       //HandleEntry he = hrf.getHandleEntry(handle);
+       String userName = "foo"; //he.getUsername();
+       if(userName == null)
+           throw new AAException("user name is null");
+
+       try{
+           if(uidSyntax == null)
+               uidSyntax = "";
+           userCtx = (DirContext)ctx.lookup(uidSyntax+"="+userName);
+       }catch(NamingException e){
+           throw new AAException("Cannot lookup context for "+userName+" :"+e);
+       }
+
+
+
+       Set s = getCombinedReleaseSet(adminArp, sharName, url, userName);
+       // go throu the set and find values for each attribute
+       try{
+           Vector sAttrs = new Vector();
+           Iterator it = s.iterator();
+           while(it.hasNext()){
+               ArpAttribute aAttr = (ArpAttribute)it.next();
+               Attribute dAttr = aAttr.getDirAttribute(userCtx, true);
+               if(dAttr != null){
+                   SAMLAttribute sAttr = jndi2saml(dAttr);
+                   sAttrs.add(sAttr);
+               }
+           }
+           SAMLAttribute[] sa = new SAMLAttribute[sAttrs.size()];
+           return (SAMLAttribute[])sAttrs.toArray(sa);
+       }catch(NamingException e){
+           throw new AAException("Bad Contexted for getting Attribute Values: "+e);
+       }
+    }
+
+
+    private Set getCombinedReleaseSet(Arp admin, String sharName, String url, String userName)
+       throws AAException {
+       
+       Set adminSet;
+       Set userSet;
+
+
+       Arp userArp = arpFactory.getInstance(userName, false);  
+       if(userArp.isNew()){
+           // no user ARP just use the admin
+           // only go throu and drop the exclude ones
+           adminSet = getReleaseSet(adminArp, sharName, url, adminArp);
+           Iterator it = adminSet.iterator();
+           while(it.hasNext()){
+               ArpAttribute attr = (ArpAttribute)it.next();
+               if(attr.mustExclude())
+                   adminSet.remove(attr);
+           }
+           return adminSet;
+       }
+
+       adminSet = getReleaseSet(adminArp, sharName, url, adminArp);
+       userSet = getReleaseSet(userArp, sharName, url, adminArp);
+       // combine the two
+       Iterator it = adminSet.iterator();
+       while(it.hasNext()){
+           ArpAttribute aAttr = (ArpAttribute)it.next();
+           if(aAttr.mustExclude()){
+               userSet.remove(aAttr);  // ok if not there
+               adminSet.remove(aAttr);
+           }
+           if(userSet.contains(aAttr)){
+               // in both. Combine filters
+               ArpFilter f = combineFilters(aAttr, getAttr(userSet, aAttr));
+               System.out.println("debug: Combine filters: "+
+                                  aAttr.getFilter()+ " AND "+
+                                  getAttr(userSet, aAttr).getFilter()+
+                                  " = " + f);
+               if(f != null)
+                   aAttr.setFilter(f, true); // force it
+               userSet.remove(aAttr);
+           }
+       }
+       adminSet.addAll(userSet);
+       return adminSet;
+
+    }              
+                   
+
+    private Set getReleaseSet(Arp arp, String sharName, String url, Arp admin)
+       throws AAException{
+
+       boolean usingDefault = false;
+
+       System.out.println("debug: using ARP: "+arp);
+
+       ArpShar shar = arp.getShar(sharName);
+       if(shar == null){
+           shar = admin.getDefaultShar();
+           usingDefault = true;
+       }
+       if(shar == null)
+           throw new AAException("No default SHAR.");
+
+       System.out.println("debug:\t using shar: "+shar+(usingDefault?"(default)":""));
+       System.out.println("debug:\t using url: "+url);
+
+       if(url == null || url.length() == 0)
+           throw new AAException("Given url to AA is null or blank");
+
+       ArpResource resource = shar.bestFit(url);
+       System.out.println("debug:\t\t best fit is: "+resource);
+       if(resource == null){
+           if(usingDefault)
+               return new HashSet(); // empty set
+
+           shar = admin.getDefaultShar();
+           if(shar == null)
+               throw new AAException("No default SHAR.");
+
+           resource = shar.bestFit(url);
+           if(resource == null)
+               return new HashSet(); // empty set
+       }
+       Set s = new HashSet();
+       ArpAttribute[] attrs = resource.getAttributes();
+       for(int i=0; i<attrs.length; i++){
+           System.out.println("debug:\t\t\t attribute: "+attrs[i]+" FILTER: "+attrs[i].getFilter());
+           s.add(attrs[i]);
+       }
+       return s;
+    }
+
+    private ArpFilter combineFilters(ArpAttribute attr1, ArpAttribute attr2){
+
+       ArpFilter filt1 = attr1.getFilter();
+       ArpFilter filt2 = attr2.getFilter();
+       
+       if(filt1 == null)
+           return filt2;
+
+       if(filt2 == null)
+           return filt1;
+
+       ArpFilterValue[]  fv1Array = filt1.getFilterValues();
+       
+       for(int i=0; i<fv1Array.length; i++){
+           ArpFilterValue afv = fv1Array[i];
+
+           if(afv.mustInclude()){  // cannot be filtered out
+               filt2.removeFilterValue(afv); // ok if not there
+           }else{
+               filt2.addAFilterValue(afv);
+           }
+       }
+
+       return filt2;
+    
+    }
+    
+
+    private ArpAttribute getAttr(Set s, ArpAttribute a){
+       Iterator it = s.iterator();
+       while(it.hasNext()){
+           ArpAttribute attr = (ArpAttribute)it.next();
+           if(attr.equals(a))
+               return attr;
+       }
+       return null;
+    }
+    
+    private SAMLAttribute jndi2saml(Attribute jAttr)
+       throws NamingException, AAException{
+
+       if(jAttr == null)
+           return null;
+           
+       String id = jAttr.getID();
+       Vector vals = new Vector();
+
+       NamingEnumeration ne = jAttr.getAll();
+       while(ne.hasMore())
+           vals.add(ne.next());
+
+
+       String[] scopes = { this.domain };
+       Object[] args = new Object[2];
+       args[0] = scopes;
+       args[1] = vals.toArray();
+
+       try{
+           Class attrClass = Class.forName(id);
+           Constructor[] cons = attrClass.getConstructors();
+           System.out.println("Got constructors for "+attrClass);
+           System.out.println("number of constructors "+cons.length);
+           System.out.println("first constructor is "+cons[0]);
+           return (SAMLAttribute)cons[0].newInstance(args);
+       }catch(Exception e){
+           throw new AAException("Failed to read the class for attribute "+id+" :"+e);
+       }
+
+    }
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AASaml.java b/src/edu/internet2/middleware/shibboleth/aa/AASaml.java
new file mode 100755 (executable)
index 0000000..1c29ec3
--- /dev/null
@@ -0,0 +1,106 @@
+package aa;
+
+import java.util.*;
+import java.io.IOException;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import edu.internet2.middleware.shibboleth.*;
+import org.w3c.dom.*;
+import org.opensaml.*;
+
+
+public class AASaml {
+
+    String[] policies = { Constants.POLICY_CLUBSHIB };
+    String protocol = SAMLBinding.SAML_SOAP_HTTPS;
+    String myName;
+    StringBuffer sharName;
+    String resource;
+    String reqID;
+    SAMLSubject sub;
+    SAMLBinding binding;
+    
+
+    public AASaml(HttpServletRequest req, String myName)
+       throws SAMLException{
+
+       binding = SAMLBindingFactory.getInstance(protocol, policies);
+       this.myName = myName;
+       sharName=new StringBuffer();
+       SAMLRequest sReq = binding.receive(req, sharName);
+       SAMLAttributeQuery q = (SAMLAttributeQuery)sReq.getQuery();
+       resource = q.getResource();
+       reqID = sReq.getRequestId();
+       sub = q.getSubject();
+    }
+       
+    public String getHandle(){
+       return sub.getName();
+    }
+
+    public String getResource(){
+       return resource;
+    }
+
+    public String getIssuer(){
+       return sub.getConfirmationData();
+    }
+
+    public String getShar(){
+       return sharName.toString();
+    }
+
+    public void respond(HttpServletResponse resp, SAMLAttribute[] attrs, SAMLException exception)
+       throws IOException{
+    
+       SAMLException ourSE = null;
+       SAMLResponse sResp = null;
+       
+       try{
+
+           SAMLSubject rSubject = new SAMLSubject(sub.getName(),
+                                              sub.getNameQualifier(),
+                                              sub.getFormat(),
+                                              sub.getConfirmationMethods(),
+                                              sub.getConfirmationData());
+            
+           SAMLStatement sStatement = new SAMLAttributeStatement(rSubject, attrs);
+           SAMLStatement[] statements = new SAMLStatement[1];
+           statements[0] = sStatement;
+           Date now = new Date();
+           Date  then = null;
+           if(attrs != null && attrs.length > 0){
+               long min = attrs[0].getLifetime();
+               for(int i = 1; i < attrs.length; i++){
+                   long t = attrs[i].getLifetime();
+                   if(t > 0 && t < min)
+                       min = t;
+               }
+               if(min > 0)
+                   then = new Date(now.getTime() + min);
+           }
+           SAMLCondition[] conditions = new SAMLCondition[1];
+           conditions[0] = new SAMLAudienceRestrictionCondition(policies);
+           SAMLAssertion sAssertion = new SAMLAssertion(myName,
+                                            now,
+                                            then,
+                                            conditions,
+                                            statements,
+                                            /* sig */ null);
+           SAMLAssertion[] assertions= new SAMLAssertion[1];
+           assertions[0] = sAssertion;
+       
+           sResp = new SAMLResponse(reqID,
+                                    /* recipient URL*/ null,
+                                    /* sig */ null,
+                                    assertions,
+                                    exception);
+       }catch (SAMLException se) {
+           ourSE = se;
+       }finally{
+           binding.respond(resp,sResp,ourSE);      
+       }
+    }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AAServlet.java b/src/edu/internet2/middleware/shibboleth/aa/AAServlet.java
new file mode 100755 (executable)
index 0000000..9a32d2f
--- /dev/null
@@ -0,0 +1,105 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+import org.opensaml.*;
+import org.w3c.dom.*;
+import edu.internet2.middleware.shibboleth.*;
+import edu.internet2.middleware.eduPerson.*;
+
+
+
+
+public class AAServlet extends HttpServlet {
+
+    String myName;
+    String dirUrl;
+    String uidSyntax;
+    String arpFactoryMethod;
+    String arpFactoryData;
+    String ctxFactory;
+    AAResponder responder;
+    //HandleRepositoryFactory hrf;
+    ArpFactory arpFactory;
+    
+    
+    public void init(ServletConfig conf)
+       throws ServletException{
+       
+       try{
+           super.init(conf);
+           myName = getInitParameter("domain");
+           dirUrl = getInitParameter("dirUrl");
+           uidSyntax = getInitParameter("ldapUserDnPhrase");
+           ctxFactory = getInitParameter("ctxFactoryClass");
+           if(ctxFactory == null)
+               ctxFactory = "com.sun.jndi.ldap.LdapCtxFactory";
+           arpFactoryMethod = getInitParameter("arpFactoryMethod");
+           arpFactoryData = getInitParameter("arpFactoryData");
+
+           //hrf = HandleRepositoryFactory.getInstance(Constants.POLICY_CLUBSHIB, this);
+           arpFactory = ArpRepository.getInstance(arpFactoryMethod, arpFactoryData);
+
+           Hashtable env = new Hashtable(11);
+           env.put(Context.INITIAL_CONTEXT_FACTORY, ctxFactory);
+
+           env.put(Context.PROVIDER_URL, dirUrl);
+           DirContext ctx = new InitialDirContext(env);
+           
+           responder = new AAResponder(/*hrf*/ null, arpFactory, ctx, myName);
+           //  }catch(HandleException he){
+           //      throw new ServletException("Init failed: "+he);
+       }catch(NamingException ne){
+           throw new ServletException("Init failed: "+ne);
+       }catch(AAException ae){
+           throw new ServletException("Init failed: "+ae);
+       }
+    }
+
+    public void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.setContentType("text/html");
+        PrintWriter out = resp.getWriter();
+       out.println("<HTML><BODY> Sorry! GET is not supported. </BODY></HTML>");
+       return;
+    }
+       
+    public void doPost(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+       SAMLAttribute[] attrs = null;
+       SAMLException ourSE = null;
+       AASaml saml = null;
+
+       try{
+           saml = new AASaml(req, myName);
+           String resource = saml.getResource();
+           String handle = saml.getHandle();
+           String shar = saml.getShar();
+           String issuedBy = saml.getIssuer();
+           System.err.println("AA debug: handle:"+handle);
+           System.err.println("AA debug: issuer:"+issuedBy);
+           System.err.println("AA debug: shar:"+shar);
+
+           attrs = responder.getReleaseAttributes(uidSyntax, handle, shar, resource);
+           System.err.println("AA debug: got attributes");
+
+       }catch (org.opensaml.SAMLException se) {
+           ourSE = se;
+           //  }catch (HandleException he) {
+           //      ourSE = new org.opensaml.SAMLException(org.opensaml.SAMLException.RESPONDER,"Bad Handle or Handle Service Problem: "+he);
+       }catch (Exception e) {
+           ourSE = new org.opensaml.SAMLException(org.opensaml.SAMLException.RESPONDER,"AA Failed with: "+e);
+       }finally{
+
+           if(saml == null)
+               throw new ServletException("AA failed to build a request: "+ourSE);
+           saml.respond(resp, attrs, ourSE);
+       }
+    }
+
+}
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AA_Acl.java b/src/edu/internet2/middleware/shibboleth/aa/AA_Acl.java
new file mode 100755 (executable)
index 0000000..878466a
--- /dev/null
@@ -0,0 +1,225 @@
+package aa;
+
+import java.util.*;
+import java.io.*;
+import java.security.acl.*;
+
+public class AA_Acl implements java.security.acl.Acl, Serializable{
+
+    HashSet positives;
+    HashSet negatives;
+    HashSet owners;
+    String name;
+
+    AA_Acl(String name, java.security.Principal root){
+       positives = new HashSet();
+       negatives = new HashSet();
+       owners = new HashSet();
+       this.name = name;
+       owners.add(root);
+    }
+
+    AA_Acl(Collection p, Collection n, String name, java.security.Principal root){
+       positives = new HashSet(p);
+       negatives = new HashSet(n);
+       owners = new HashSet();
+       this.name = name;
+       owners.add(root);
+    }
+
+    /////// Methods //////////
+
+    public boolean addEntry(java.security.Principal p, AclEntry entry)throws NotOwnerException{
+
+       if(this.isOwner(p) == false)
+           throw new NotOwnerException();
+       if(entry.isNegative()){
+           if(negatives.contains(entry)){
+               return false;
+           }else{
+               negatives.add(entry);
+               return true;
+           }
+       }else{  // is positive ACL
+           if(positives.contains(entry)){
+               return false;
+           }else{
+               positives.add(entry);
+               return true;
+           }
+       }
+    }
+
+    public boolean checkPermission(java.security.Principal user, java.security.acl.Permission perm){
+       for(Iterator it = positives.iterator(); it.hasNext();){
+           AclEntry entry = (AclEntry)it.next();
+           java.security.Principal p = entry.getPrincipal();
+           if(p.equals(user)){
+               if(entry.checkPermission(perm)){
+                   //make sure it is not in negative list
+                   for(Iterator it2 = negatives.iterator(); it2.hasNext();){
+                       AclEntry entry2 = (AclEntry)it2.next();
+                       java.security.Principal p2 = entry2.getPrincipal();
+                       if(p2.equals(user)){
+                           if(entry2.checkPermission(perm)){
+                               return false; // in both list
+                           }
+                           continue;
+                       }
+                   }
+                   // not in negative list
+                   return true;  // give permission
+               }else{
+                   continue;
+               }
+           }else{
+               continue;
+           }
+       }
+       return false;  // not in any positive entry
+    }
+
+    public Enumeration entries(){
+       return new AclEntryEnumeration(positives, negatives);
+    }
+
+    public String getName(){
+       return name;
+    }
+
+    public Enumeration getPermissions(java.security.Principal user){
+       return new AclPermissionEnumeration(user, positives, negatives);
+    }
+
+    public boolean removeEntry(java.security.Principal caller, AclEntry entry)
+    throws NotOwnerException{
+       
+       if(this.isOwner(caller) == false)
+           throw new NotOwnerException();
+       if(entry.isNegative()){
+           if(negatives.contains(entry)){
+               negatives.remove(entry);
+               return true;
+           }else{
+               return false;
+           }
+       }else{  // is positive ACL
+           if(positives.contains(entry)){
+               positives.remove(entry);
+               return true;
+           }else{
+               return false;
+           }
+       }
+    }
+
+
+    public void setName(java.security.Principal caller, String name)
+       throws NotOwnerException{
+       if(this.isOwner(caller) == false)
+           throw new NotOwnerException();
+       this.name = name;
+    }
+
+    public String toString(){
+       return name+
+           "{"
+           +positives
+           +"}{"
+           +negatives
+           +"}";
+
+    }
+
+    /////////// Owner methods ///////////////
+    public boolean addOwner(java.security.Principal caller, java.security.Principal owner)
+       throws NotOwnerException{
+       if(owners.contains(caller) == false)
+           throw new NotOwnerException();
+       return owners.add(owner);
+    }
+
+    public boolean deleteOwner(java.security.Principal caller, java.security.Principal owner)
+       throws NotOwnerException,
+        LastOwnerException{
+       if(owners.contains(caller) == false)
+           throw new NotOwnerException();
+       return owners.remove(owner);    
+    }
+
+    public boolean isOwner(java.security.Principal owner){
+       return owners.contains(owner);
+    }
+       
+    
+}
+class AclEntryEnumeration implements java.util.Enumeration{
+    HashSet entries;
+    Iterator it;
+
+    AclEntryEnumeration(HashSet p, HashSet n){
+       entries = p;
+       entries.addAll(n);  
+       it = entries.iterator();
+    }
+
+    public boolean hasMoreElements(){
+       return it.hasNext();
+    }
+
+    public Object nextElement(){
+       return it.next();
+    }
+}
+
+
+
+class AclPermissionEnumeration implements java.util.Enumeration{
+    HashSet permissions;
+    Iterator it;
+
+    AclPermissionEnumeration(java.security.Principal user, HashSet p, HashSet n){
+       permissions = new HashSet();
+       // go throu entries and find the one for this user
+       for(Iterator i = p.iterator(); i.hasNext();){
+           AclEntry ae = (AclEntry)i.next();
+           if(ae.getPrincipal().equals(user)){
+               // go throu permissions and add it to enum
+               for(Enumeration j=ae.permissions(); j.hasMoreElements();){
+                   permissions.add((Permission)j.nextElement());
+               }
+           }
+       }
+       // now go throu negatives and either add it or remove positve one
+       for(Iterator i = n.iterator(); i.hasNext();){
+           AclEntry ae = (AclEntry)i.next();
+           if(ae.getPrincipal().equals(user)){
+               // go throu permissions and check it
+               for(Enumeration j=ae.permissions(); j.hasMoreElements();){
+                   Permission perm = (Permission)j.nextElement();
+                   if(permissions.contains(perm)){
+                       permissions.remove(perm);
+                   }else{
+                       permissions.add(perm);
+                   }
+               }
+           }
+       }
+
+       it = permissions.iterator();
+    }
+
+    public boolean hasMoreElements(){
+       return it.hasNext();
+    }
+
+    public Object nextElement(){
+       return it.next();
+    }
+}
+
+
+
+
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AA_AclEntry.java b/src/edu/internet2/middleware/shibboleth/aa/AA_AclEntry.java
new file mode 100755 (executable)
index 0000000..32cacc6
--- /dev/null
@@ -0,0 +1,116 @@
+package aa;
+
+import java.util.*;
+import java.io.*;
+import java.security.acl.*;
+import java.security.*;
+
+public class AA_AclEntry implements java.security.acl.AclEntry, Serializable{
+
+    HashSet permissions;
+    boolean isNegative;
+    Principal principal;
+
+    AA_AclEntry(Principal p){
+       permissions = new HashSet();
+       isNegative = false;
+       principal = p;
+    }
+
+    AA_AclEntry(Collection c, boolean n, Principal p){
+       permissions = new HashSet(c);
+       isNegative = n;
+       principal = p;
+    }
+
+    /////// Methods //////////
+
+    public boolean addPermission(java.security.acl.Permission p){
+       return permissions.add(p);
+    }
+
+    public boolean checkPermission(java.security.acl.Permission p){
+       if(permissions.contains(new AA_Permission(AA_Permission.ALL)))
+           return true;
+       boolean rc = permissions.contains(p);
+       return rc;
+    }
+
+    public Object clone(){
+       return new AA_AclEntry(permissions, isNegative, principal);
+    }
+
+    public Principal getPrincipal(){
+       return principal;
+    }
+
+    public boolean isNegative(){
+       return isNegative;
+    }
+
+    public Enumeration permissions(){
+       return new PermissionsEnumeration(permissions);
+    }
+
+    public boolean removePermission(java.security.acl.Permission p){
+       return permissions.remove(p);
+    }
+
+    public void setNegativePermissions(){
+       isNegative = true;
+    }
+
+    public boolean setPrincipal(Principal p){
+       if(principal != null){
+           return false;
+       }else{
+           principal = p;
+           return true;
+       }
+    }
+
+    public String toString(){
+       return (isNegative?"-":"+")
+           +principal
+           +"("
+           +permissions
+           +")";
+    }
+
+    public boolean equals(Object o){
+       AclEntry ae = (AclEntry)o;
+       if(this.principal.equals(ae.getPrincipal()) && 
+          (ae.isNegative() == isNegative))
+           return true;
+       return false;
+    }
+
+    public int hashCode(){
+       return principal.hashCode();
+    }
+          
+    
+}
+
+class PermissionsEnumeration implements java.util.Enumeration{
+    HashSet perms;
+    Iterator it;
+
+    PermissionsEnumeration(HashSet p){
+       perms = p;
+       it = perms.iterator();
+    }
+
+    public boolean hasMoreElements(){
+       return it.hasNext();
+    }
+
+    public Object nextElement(){
+       return it.next();
+    }
+}
+
+
+
+
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AA_Identity.java b/src/edu/internet2/middleware/shibboleth/aa/AA_Identity.java
new file mode 100755 (executable)
index 0000000..576a1ce
--- /dev/null
@@ -0,0 +1,35 @@
+package aa;
+
+import java.security.*;
+import java.io.*;
+
+public class AA_Identity implements java.security.Principal, Serializable{
+
+    String ident;
+
+    public AA_Identity(String ident){
+       this.ident = ident;
+    }
+
+    /////// Methods //////////
+
+    public boolean equals(Object o){
+       return (ident.equalsIgnoreCase(o.toString()));
+    }
+
+    public String getName(){
+       return ident;
+    }
+
+    public String toString(){
+       return ident;
+    }
+    public int hashCode(){
+       return ident.hashCode();
+    }
+}
+
+
+
+
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/AA_Permission.java b/src/edu/internet2/middleware/shibboleth/aa/AA_Permission.java
new file mode 100755 (executable)
index 0000000..882792c
--- /dev/null
@@ -0,0 +1,50 @@
+package aa;
+
+import java.security.acl.*;
+import java.io.*;
+public class AA_Permission implements java.security.acl.Permission, Serializable{
+
+    protected static int LOOKUP = 0;
+    protected static int READ = 1;
+    protected static int WRITE = 2;
+    protected static int INSERT = 3;
+    protected static int DELETE = 4;
+    protected static int ALL = 5;
+
+    protected static String names[] = {
+       "LOOKUP",
+       "READ",
+       "WRITE",
+       "INSERT",
+       "DELETE",
+       "ALL"};
+
+
+    int permission;
+
+    AA_Permission(int p){
+       permission = p;
+    }
+
+    /////// Methods //////////
+
+    public boolean equals(Object o){
+       return (permission == ((AA_Permission)o).getIntVal());
+    }
+
+    public int getIntVal(){
+       return permission;
+    }
+
+    public String toString(){
+       return names[permission];
+    }
+    public int hashCode(){
+       return permission+1;
+    }
+}
+
+
+
+
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/Arp.java b/src/edu/internet2/middleware/shibboleth/aa/Arp.java
new file mode 100755 (executable)
index 0000000..4bfd15b
--- /dev/null
@@ -0,0 +1,179 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+import java.security.Principal;
+import java.security.acl.*;
+
+public class Arp extends ArpCore implements Serializable{
+
+    // Attributes
+    protected String name;
+    protected boolean isAdmin;
+    private boolean everWritten = false;
+    private Date lastRead;
+    private boolean hasDefaultShar = false;
+    private ArpShar defaultShar;
+
+    // Associations
+    protected Vector  shars;
+
+    // Constructors
+    public Arp(String name, boolean isAdmin)
+       throws NotOwnerException{
+
+       this.name = name;
+       this.isAdmin = isAdmin;
+       shars  = new Vector();
+       makeAcl("arpAcl");
+    }
+
+    // Operations
+    public boolean isNew(){
+       return !everWritten;
+    }
+
+    public void setNew(boolean b){
+       everWritten = !b;
+    }
+
+    public void setLastRead(Date d){
+       lastRead = d;
+    }
+
+    public Date getLastRead(){
+       return lastRead;
+    }
+
+    /**
+     * Add a new SHAR to the list of SHARs for this ARP.
+     * returns false and does not replace if SHAR already exists.
+     */
+    public boolean addAShar(String name, boolean isDefault)
+       throws NotOwnerException,AAPermissionException, AAException{
+
+       if(isDefault && hasDefaultShar)
+           throw new AAException("Already has a Default SHAR");
+
+       ArpShar newShar = new ArpShar(name, isDefault);
+       if(shars.contains(newShar))
+           return false; // already there
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());
+       shars.add(newShar);
+       if(isDefault){
+           hasDefaultShar = true;
+           defaultShar = newShar;
+       }
+       return true;
+    }
+
+    /**
+     * Add the given SHAR to the list of SHARs for this ARP.
+     * returns false and does not replace if SHAR already exists.
+     */
+    public boolean addAShar(ArpShar shar)
+       throws AAPermissionException, AAException{
+
+       return addAShar(shar, false);
+    }
+
+    /**
+     * Adds the given shar to the shars for this Arp.
+     * if force flag is true and shar already exists
+     * then replaces the existing reource otherwise leaves the existing 
+     * shar untouched.  
+     * returns false if reource already existed.
+     * Throws AAPermissionException if caller is not permitted to insert or replace.
+     */
+    public boolean addAShar(ArpShar shar, boolean force)
+       throws AAPermissionException, AAException {
+               
+       if(shars.contains(shar)){
+           if(force){
+               if(! replacePermitted())
+                   throw new AAPermissionException("No replace right for "+getCaller());
+               shars.remove(shar);
+               shars.add(shar);
+           }
+           return false; // already there
+       }
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());
+       if(shar.isDefault() &&  hasDefaultShar)
+           throw new AAException("Already has a Default SHAR");
+
+       shars.add(shar);
+       if(shar.isDefault()){
+           hasDefaultShar = true;
+           defaultShar = shar;
+       }
+       return true;
+    }
+
+
+
+    public boolean removeAShar(String name)
+       throws NotOwnerException, AAPermissionException{
+
+       ArpShar newShar = new ArpShar(name, false);
+       if(shars.contains(newShar)){
+           if(! removePermitted())
+               throw new AAPermissionException("No DELETE rights for "+getCaller());
+           shars.remove(newShar);
+           if(hasDefaultShar && newShar.equals(defaultShar)){
+               defaultShar = null;
+               hasDefaultShar = false;
+           }
+           return true;
+       }
+       return false; // not found
+    }
+
+
+    public ArpShar getShar(String name) {
+       Enumeration en = shars.elements();
+       while(en.hasMoreElements()){
+           ArpShar aShar = (ArpShar)en.nextElement();
+           if(aShar.getName().equals(name))
+               return aShar;
+       }
+       return null;
+    }
+
+    public ArpShar[] getShars() {
+       int len = shars.size();
+       ArpShar[] a = new ArpShar[len];
+       for(int i = 0; i < len; i++)
+           a[i] = (ArpShar)shars.get(i);
+       return a;
+    }
+
+    public ArpShar getDefaultShar(){
+       return defaultShar;
+    }
+
+    public String getName(){
+       return name;
+    }
+
+    //public void setAcl(Acl acl){
+    //this.acl = acl;
+    //}
+
+    //    public String urlToShar(String url) {
+    //    }
+
+    public String toString(){
+       return name+(isAdmin?"(admin)":"");
+    }
+
+    public boolean isAdmin(){
+       return isAdmin;
+    }
+
+    public boolean equals(Object arp){
+       return name.equals(((Arp)arp).getName());
+    }
+
+} /* end class Arp */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpAttribute.java b/src/edu/internet2/middleware/shibboleth/aa/ArpAttribute.java
new file mode 100755 (executable)
index 0000000..7ca2f77
--- /dev/null
@@ -0,0 +1,98 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+import javax.naming.directory.*;
+
+public class ArpAttribute implements Serializable{
+
+    // Attributes
+    protected String ID;
+    protected boolean exclude;
+
+    // Associations
+    protected ArpFilter filter;
+
+    // Constructor
+    public ArpAttribute(String ID, boolean exclude){
+       this.ID = ID;
+       this.exclude = exclude;
+    }
+
+    // Operations
+    public Attribute getDirAttribute(DirContext ctx, boolean doFilter)
+       throws javax.naming.NamingException{
+
+       String[] ids = new String[1];
+       ids[0] = ID;
+       Attributes attrs = ctx.getAttributes("", ids);
+       Attribute attr = attrs.get(ID);
+
+       if(doFilter && hasFilter()){
+           ArpFilterValue[] fvArray = filter.getFilterValues();
+           for(int i=0; i < fvArray.length; i++){
+               if(fvArray[i].mustInclude())
+                   ; //skip. do not filter.
+               else
+                   attr.remove(fvArray[i].getValue());
+           }
+       }
+       return attr;
+    }
+
+
+    public String getName(){
+       return ID;
+    }
+
+    /**
+     * lists all known attribute names.  Probably by consulting a 
+     * database or LDAP schemas
+     */
+    public String[] list(){
+       return null;
+    }
+
+    public boolean hasFilter(){
+       if(filter == null)
+           return false;
+       return true;
+    }
+
+    public ArpFilter getFilter(){
+       return filter;
+    }
+
+    /**
+     * sets a filter for this attribute.  returns true if succeeds
+     * returns false if there is already a filter set.
+     * If flag Force is true it replaces the existing filter,
+     * otherwise does not replace the existing filter.
+     */
+    public boolean setFilter(ArpFilter filter, boolean force){
+       if(hasFilter()){
+           if(force)
+               this.filter = filter;
+           return false;
+       }
+       this.filter = filter;
+       return true;
+    }
+    
+    public boolean mustExclude(){
+       return exclude;
+    }
+
+    public boolean equals(Object attr){
+       return ID.equals(((ArpAttribute)attr).getName());
+    }
+
+    public int hashCode(){
+       return ID.hashCode();
+    }
+
+    public String toString(){
+       return ID+(exclude?"(exclude)":"");
+    }
+
+} /* end class ArpAttribute */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpCore.java b/src/edu/internet2/middleware/shibboleth/aa/ArpCore.java
new file mode 100755 (executable)
index 0000000..c0b0826
--- /dev/null
@@ -0,0 +1,135 @@
+package aa;
+
+import java.util.Enumeration;
+import java.security.Principal;
+import java.security.acl.*;
+import java.io.Serializable;
+
+public class ArpCore implements Serializable{
+
+    // Attributes
+    protected String userEnv = "user.name";
+    protected Acl acl;
+
+    // Associations
+
+    // Constructors
+
+
+    // Operations
+    public Principal getCaller(){
+       // return new KerberosPrincipal(System.getProperty(userEnv));
+       return new AA_Identity(System.getProperty(userEnv));
+    }
+
+    public void makeAcl(String name)throws NotOwnerException{
+       Principal owner = getCaller();
+       acl = new AA_Acl(name, owner);
+       AclEntry entry = new AA_AclEntry(owner);
+       entry.addPermission(new AA_Permission(AA_Permission.ALL));
+       acl.addEntry(owner, entry);
+    }
+
+
+    public Acl getAcl(){
+       return acl;
+    }
+
+    public void setAcl(String user, String permit)
+       throws AAPermissionException, NotOwnerException{
+
+       Principal prince = new AA_Identity(user);
+       if(permit.equalsIgnoreCase("NONE")){
+           setAcl(prince, null);
+           return;
+       }
+       String[] permitNames = AA_Permission.names;
+       for(int i=0; i < permitNames.length; i++){
+           if(permitNames[i].equalsIgnoreCase(permit)){
+               setAcl(prince, new AA_Permission(i));
+               return;
+           }
+       }
+       throw new AAPermissionException("No such ACL: "+permit);
+    }
+
+    public void setAcl(Principal user, Permission permit)
+       throws NotOwnerException, AAPermissionException{
+
+       if(!setAclPermitted())
+           throw new AAPermissionException("ALL access is needed to set ACL.");
+       if(permit == null){
+           AclEntry entry = getAclEntry(user);
+           if(entry == null)
+               throw new AAPermissionException("No ACL entry found for user: "+user);
+           if(!acl.removeEntry(getCaller(), entry))
+               throw new AAPermissionException("No ACL entry found. System Eror");
+           return;
+       }
+
+       if(acl.checkPermission(user, permit))
+           return; // already has it
+       AclEntry entry = getAclEntry(user);
+       if(entry == null){
+           entry = new AA_AclEntry(user);
+           entry.addPermission(permit);
+           acl.addEntry(getCaller(), entry);
+       }else{
+           entry.addPermission(permit);
+       }
+       return;
+    }
+
+    private AclEntry getAclEntry(Principal user){
+       AclEntry entry = null;
+
+       Enumeration en = acl.entries();
+       while(en.hasMoreElements()){
+           entry = (AclEntry)en.nextElement();
+           if(entry.getPrincipal().equals(user))
+               return entry;
+       }
+       return null;
+    }
+
+       
+    /**
+     * Check to see if caller has permission to remove and insert (i.e replace) for this object.
+     * Returns true if permitted.
+     */
+    
+    public boolean replacePermitted(){
+       Permission rm = new AA_Permission(AA_Permission.DELETE);
+       Permission add = new AA_Permission(AA_Permission.INSERT);
+       Principal user = getCaller();
+       if(acl.checkPermission(user, rm) && acl.checkPermission(user, add))
+           return true;
+       return false;
+    }
+
+    public boolean insertPermitted(){
+       Permission add = new AA_Permission(AA_Permission.INSERT);
+       if(acl.checkPermission(getCaller(), add))
+           return true;
+       return false;
+    }
+
+    public boolean removePermitted(){
+       Permission rm = new AA_Permission(AA_Permission.DELETE);
+       if(acl.checkPermission(getCaller(), rm))
+           return true;
+       return false;
+    }
+
+    public boolean setAclPermitted(){
+       Permission all = new AA_Permission(AA_Permission.ALL);
+       if(acl.checkPermission(getCaller(), all))
+           return true;
+       return false;
+    }
+
+
+           
+
+
+} /* end class ArpCore */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpFactory.java b/src/edu/internet2/middleware/shibboleth/aa/ArpFactory.java
new file mode 100755 (executable)
index 0000000..35e5f25
--- /dev/null
@@ -0,0 +1,36 @@
+package aa;
+
+public interface ArpFactory{
+
+
+    /**
+     * Returns an Arp instance. It tries to retrieve the Arp from a repository
+     * If not found then creates a new emplty Arp.  
+     * Arp can be check by its isNew() to see how it was generated
+     */
+
+    public Arp getInstance(String arpName, boolean isDefault)
+       throws AAException;
+
+    
+    /**
+     * Writes the given ARP back to the repository.
+     */
+
+    public void write(Arp arp) throws AAException;
+
+    /**
+     * Rereads the ARP if the version on storage is newer
+     * than the one in memory.
+     */
+
+    public Arp reread(Arp arp) throws AAException;
+
+    /**
+     * Permanently removes the given ARP from the repository
+     */
+
+    public void remove(Arp arp) throws AAException;
+
+}
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpFileFactory.java b/src/edu/internet2/middleware/shibboleth/aa/ArpFileFactory.java
new file mode 100755 (executable)
index 0000000..b947e5d
--- /dev/null
@@ -0,0 +1,98 @@
+package aa;
+
+import java.io.*;
+import java.util.Date;
+import java.security.acl.*;
+import java.security.Principal;
+//import javax.security.auth.kerberos.KerberosPrincipal;
+
+public class ArpFileFactory implements ArpFactory{
+
+    static String dataStore;
+
+    public ArpFileFactory(String pathData){
+       dataStore = pathData;
+    }
+
+    /**
+     * returns an Arp instance. It tries to retrieve the Arp from file system
+     * If not found then creates a new emplty Arp.  
+     * Arp can be check by its isNew() to see how it was generated
+     */
+
+    public Arp getInstance(String arpName, boolean isAdmin)
+    throws AAException{
+       try{
+           String fileName = dataStore+System.getProperty("file.separator")+arpName;
+
+           FileInputStream f = new FileInputStream(fileName);
+           ObjectInput s = new ObjectInputStream(f);
+           Arp arp = (Arp)s.readObject();
+           if(!arpName.equals(arp.getName()))
+              throw new AAException("Wrong ARP name.  ARP maybe renamed in datastore. ");
+           arp.setNew(false);
+           arp.setLastRead(new Date());
+           return arp;
+           
+       }catch(FileNotFoundException e){
+           // check the IO error to make sure "file not found"
+           try{
+               Arp arp = new Arp(arpName, isAdmin);
+               arp.setNew(true);
+               arp.setLastRead(new Date());
+               return arp;
+           }catch(NotOwnerException noe){
+               throw new AAException("Cannot create an ARP. Not owner.");
+           }
+
+       }catch(IOException fe){
+           throw new AAException("Reading ARP failed: "+fe);
+       }catch(ClassNotFoundException ce){
+           throw new AAException("ARP retrival failed: "+ce);
+       }catch(Exception oe){
+           throw new AAException(oe.toString());
+       }
+    }
+
+    public void write(Arp arp) throws AAException{
+       // XXX do we need to check any permissions?
+       try{
+           String fileName = dataStore+System.getProperty("file.separator")+arp.getName();
+           FileOutputStream f = new FileOutputStream(fileName);
+           ObjectOutput s = new ObjectOutputStream(f);
+           arp.setNew(false);
+           s.writeObject(arp);
+           s.flush();      
+       }catch(IOException e){
+           throw new AAException("IO Problem:"+e);
+       }
+    }
+
+    /**
+     * Reread the arp from file system if the copy on disk
+     * is newer than the copy in memory.
+     */
+
+    public Arp reread(Arp arp) throws AAException{
+       String fileName = dataStore+System.getProperty("file.separator")+arp.getName();
+       File file = new File(fileName);
+       if(file == null)
+           throw new AAException("Arp not found on disk while trying to re-read. :"+arp);
+       Date timeStamp = new Date(file.lastModified());
+       if(timeStamp.after(arp.getLastRead())){
+           return getInstance(arp.getName(), arp.isAdmin());
+       }
+       return arp;  // return the old one.
+    }
+
+    public void remove(Arp arp) throws AAException{
+       try{
+           String fileName = dataStore+System.getProperty("file.separator")+arp.getName();
+           File f = new File(fileName);
+           f.delete();
+       }catch(Exception e){
+           throw new AAException("IO Problem:"+e);
+       }
+    }
+}
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpFilter.java b/src/edu/internet2/middleware/shibboleth/aa/ArpFilter.java
new file mode 100755 (executable)
index 0000000..3a10ad3
--- /dev/null
@@ -0,0 +1,80 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+public class ArpFilter implements Serializable{
+
+
+    // Associations
+    protected Vector values;
+    
+    // Constructor
+    public ArpFilter(){
+       values = new Vector();
+    }
+
+    // Operations
+    public ArpFilterValue[] getFilterValues() {
+       ArpFilterValue[] afva = new ArpFilterValue[values.size()];
+       return (ArpFilterValue[])values.toArray(afva);
+    }
+
+    public boolean addAFilterValue(ArpFilterValue afv) {
+       return addAFilterValue(afv, false);
+    }
+
+    /**
+     * Adds the given value to the values for this Filter.
+     * if force flag is true and value already exists
+     * then replaces the existing reource otherwise leaves the existing 
+     * value untouched.  
+     * returns false if reource already existed.
+     */
+    public boolean addAFilterValue(ArpFilterValue afv, boolean force) {
+       if(values.contains(afv)){
+           if(force){
+               values.remove(afv);
+               values.add(afv);
+           }
+           return false; // already there
+       }
+       values.add(afv);
+       return true;
+    }
+
+    public boolean removeFilterValue(ArpFilterValue afv) {
+       if(values.contains(afv)){
+           values.remove(afv);
+           return true;
+       }
+       return false; // not found
+    }
+
+    public boolean contains(ArpFilterValue afv) {
+       return values.contains(afv);
+    }
+
+    public ArpFilterValue[] getInclusions() {
+       Vector incs = new Vector();
+       Enumeration en = values.elements();
+       while(en.hasMoreElements()){
+           ArpFilterValue afv = (ArpFilterValue)en.nextElement();
+           if(afv.mustInclude())
+               incs.add(afv);
+       }
+       return (ArpFilterValue[])incs.toArray();
+    }
+    
+    public String toString(){
+       StringBuffer buf = new StringBuffer();
+       Enumeration en = values.elements();
+       while(en.hasMoreElements()){
+           buf.append((ArpFilterValue)en.nextElement());
+           buf.append(", ");
+       }
+       return buf.toString();
+    }
+       
+
+} /* end class ArpFilter */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpFilterValue.java b/src/edu/internet2/middleware/shibboleth/aa/ArpFilterValue.java
new file mode 100755 (executable)
index 0000000..82fd5c4
--- /dev/null
@@ -0,0 +1,36 @@
+package aa;
+
+import java.io.*;
+public class ArpFilterValue implements Serializable{
+
+
+    // Associations
+    protected Object value;
+    protected boolean include;
+
+
+    // Constructor
+    public ArpFilterValue(Object value, boolean include){
+       this.value = value;
+       this.include = include;
+    }
+
+    // Operations
+
+    public boolean mustInclude(){
+       return include; 
+    }
+
+    public Object getValue(){
+       return value;
+    }
+    
+    public boolean equlas(Object afv){
+       return value.equals(((ArpFilterValue)afv).getValue());
+    }
+
+    public String toString(){
+       return value+(include?"(include)":"");
+    }
+
+} /* end class ArpFilterValue */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpRepository.java b/src/edu/internet2/middleware/shibboleth/aa/ArpRepository.java
new file mode 100755 (executable)
index 0000000..422cb63
--- /dev/null
@@ -0,0 +1,24 @@
+package aa;
+
+public class ArpRepository{
+
+
+    /**
+     * This is a method to allow implementation of different 
+     * repositories for ARPs. e.g. File system, SQL database, or LDAP
+     * It returns an implementation based on the given method.  
+     * It passes the given data string to the implementation.  Data string is 
+     * opeque and only meaningful to the specific implementation.
+     * e.g. it might be a directory path to file system implementation.
+     */
+
+    public static ArpFactory getInstance(String method, String pathData)
+       throws AAException{
+       if(method.equalsIgnoreCase("file"))
+           return new ArpFileFactory(pathData);
+       else
+           throw new AAException("Unknown repository or not implemented yet:" +method);
+
+    }
+}
+
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpResource.java b/src/edu/internet2/middleware/shibboleth/aa/ArpResource.java
new file mode 100755 (executable)
index 0000000..2707ac3
--- /dev/null
@@ -0,0 +1,120 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+import java.security.acl.*;
+
+public class ArpResource extends ArpCore implements Serializable{
+
+    // Attributes
+    protected String name;
+
+    // Associations
+    protected TName tName;
+    protected Vector attributes;
+    protected AA_Acl acl;
+
+    // constructor
+    public ArpResource(String name) throws NotOwnerException{
+       this.name = name;
+       tName = new TName(name);
+       attributes = new Vector();
+       makeAcl("resourceAcl");
+    }
+
+    // Operations
+    public String toString() {
+       return name+" ["+tName+"]";
+    }
+
+
+    public boolean addAnAttribute(String name, boolean exclude)
+       throws AAPermissionException{
+
+       if(attributes.contains(new ArpAttribute(name, exclude)))
+           return false; // already there
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());
+       attributes.add(new ArpAttribute(name, exclude));
+       return true;
+    }
+
+    public boolean addAnAttribute(ArpAttribute attr)
+       throws AAPermissionException{
+       return addAnAttribute(attr, false);
+    }
+
+    /**
+     * Adds the given attribute to the attributes for this Resource.
+     * if force flag is true and attribute already exists
+     * then replaces the existing reource otherwise leaves the existing 
+     * attribute untouched.  
+     * returns false if reource already existed.
+     */
+    public boolean addAnAttribute(ArpAttribute attr, boolean force)
+       throws AAPermissionException {
+
+       if(attributes.contains(attr)){
+           if(force){
+               if(! replacePermitted())
+                   throw new AAPermissionException("No replace right for "+getCaller());               
+               attributes.remove(attr);
+               attributes.add(attr);
+           }
+           return false; // already there
+       }
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());        
+       attributes.add(attr);
+       return true;
+    }
+
+    public boolean removeAnAttribute(String name)
+       throws AAPermissionException {
+
+       if(attributes.contains(new ArpAttribute(name, false))){
+           if(! insertPermitted())
+               throw new AAPermissionException("No DELETE right for "+getCaller());        
+           attributes.remove(new ArpAttribute(name, false));
+           return true;
+       }
+       return false; // not found
+    }
+
+    public ArpAttribute getAttribute(String name) {
+       Enumeration en = attributes.elements();
+       while(en.hasMoreElements()){
+           ArpAttribute aAttribute = (ArpAttribute)en.nextElement();
+           if(aAttribute.getName().equals(name))
+               return aAttribute;
+       }
+       return null;
+    }
+
+    public ArpAttribute[] getAttributes() {
+       int len = attributes.size();
+       ArpAttribute[] a = new ArpAttribute[len];
+       for(int i = 0; i < len; i++)
+           a[i] = (ArpAttribute)attributes.get(i);
+       return a;
+    }
+
+
+    public int fit(String resrcName) {
+       TName tn = new TName(resrcName);
+       return tName.compare(tn);
+    }
+
+    public TName getTName(){
+       return tName;
+    }
+
+    public String getName(){
+       return name;
+    }
+
+    public boolean equals(Object rsrc){
+       return name.equals(((ArpResource)rsrc).getName());
+    }
+
+} /* end class ArpResource */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/ArpShar.java b/src/edu/internet2/middleware/shibboleth/aa/ArpShar.java
new file mode 100755 (executable)
index 0000000..76e05ab
--- /dev/null
@@ -0,0 +1,144 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+import java.security.acl.*;
+
+public class ArpShar extends ArpCore implements Serializable{
+
+    // Attributes
+    protected String name;
+    protected boolean isDefault;
+
+    // Associations
+    protected Vector  resources;
+    protected AA_Acl acl;
+
+    // Construstor
+    public ArpShar(String name, boolean isDefault)throws NotOwnerException{
+       this.name = name;
+       this.isDefault = isDefault;
+       resources  = new Vector();
+       makeAcl("sharAcl");
+    }
+
+    // Operations
+    public String toString() {
+       return name+(isDefault?"(default)":"");
+    }
+
+    public boolean isDefault(){
+       return isDefault;
+    }
+
+    public boolean addAResource(String url)
+       throws NotOwnerException,AAPermissionException{
+
+       if(resources.contains(new ArpResource(url)))
+           return false; // already there
+
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());
+
+       resources.add(new ArpResource(url));
+       return true;
+    }
+
+    /**
+     * Adds a given resource to the resources for this Shar.
+     * Does not replace if resource already exists.
+     * returns false if resource already exists.
+     */
+
+    public boolean addAResource(ArpResource rsrc) 
+       throws AAPermissionException{
+       return addAResource(rsrc, false);
+    }
+
+    /**
+     * Adds the given resource to the resources for this Shar.
+     * if force flag is true and resource already exists
+     * then replaces the existing reource otherwise leaves the existing 
+     * resource untouched.  
+     * returns false if reource already existed.
+     */
+    public boolean addAResource(ArpResource rsrc, boolean force)
+       throws AAPermissionException{
+
+       if(resources.contains(rsrc)){
+           if(force){
+               if(! replacePermitted())
+                   throw new AAPermissionException("No replace right for "+getCaller());
+               resources.remove(rsrc);
+               resources.add(rsrc);
+           }
+           return false; // already there
+       }
+       if(! insertPermitted())
+           throw new AAPermissionException("No INSERT right for "+getCaller());
+       resources.add(rsrc);
+       return true;
+    }
+
+    public boolean removeAResource(String url)
+       throws NotOwnerException, AAPermissionException{
+       if(resources.contains(new ArpResource(url))){
+           if(! removePermitted())
+               throw new AAPermissionException("No DELETE right for "+getCaller());
+           resources.remove(new ArpResource(url));
+           return true;
+       }
+       return false; // not found
+    }
+
+    public ArpResource getResource(String url) {
+       Enumeration en = resources.elements();
+       while(en.hasMoreElements()){
+           ArpResource aResource = (ArpResource)en.nextElement();
+           if(aResource.getName().equals(url))
+               return aResource;
+       }
+       return null;
+    }
+
+    public ArpResource[] getResources() {
+       int len = resources.size();
+       ArpResource[] a = new ArpResource[len];
+       for(int i = 0; i < len; i++)
+           a[i] = (ArpResource)resources.get(i);
+       return a;
+    }
+
+
+    /**
+     * Go throu all resource objects and find the one that
+     * best matches the given url.  This is based on comparison 
+     * of TNames of urls provided by fit method of ArpResource.
+     *
+     * returns an ArpResource or null if no match found;
+     */
+    public ArpResource bestFit(String url) {
+
+       ArpResource[] ara = new ArpResource[resources.size()];
+       ara = (ArpResource[])resources.toArray(ara);
+       int bestScore = 0;
+       ArpResource bestResource = null;
+       for(int i=0; i < ara.length; i++){
+           int score =  ara[i].fit(url);
+           if(score > bestScore){
+               bestScore = score;
+               bestResource = ara[i];
+           }
+       }
+       return bestResource;
+    }
+
+    public String getName(){
+       return name;
+    }
+
+    public boolean equals(Object shar){
+       return name.equals(((ArpShar)shar).getName());
+    }
+
+} /* end class ArpShar */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/TName.java b/src/edu/internet2/middleware/shibboleth/aa/TName.java
new file mode 100755 (executable)
index 0000000..549331a
--- /dev/null
@@ -0,0 +1,78 @@
+package aa;
+
+import java.io.*;
+import java.util.*;
+class TName implements Serializable{
+
+    // Attributes
+    private String name;
+    private String[] tokens;
+    final static String WILD = "*";
+
+    // Associations
+    protected ArpResource myArpResource;
+
+    // Constructors
+    /** 
+     * This class is a tokenized reprezentation of a URL so 
+     * URLs can be compared against each other and see what is
+     * the best match or best fit.
+     */
+    TName(String url){
+       // break down the url and store it in a String[]
+       if(url.startsWith("http://"))
+           url = url.substring(7);
+       if(url.startsWith("https://"))
+           url = url.substring(8);
+
+       int i = 0;
+       StringTokenizer slash = new StringTokenizer(url, ":/\\");
+       if(slash.hasMoreTokens()){
+           // first element generally host name
+           String hostname = slash.nextToken();
+           StringTokenizer dot = new StringTokenizer(hostname, ".");
+           int count = dot.countTokens();
+           tokens = new String[count+slash.countTokens()];
+           for(int n = count; n > 0;  n--){
+               tokens[n-1] = dot.nextToken();
+           }
+           i += count;
+       }
+       while(slash.hasMoreTokens()){
+           tokens[i++] = slash.nextToken();
+       }
+    }
+
+    // Operations
+    public String[] getTokens() {
+       return tokens;
+    }
+
+    public int compare(TName t){
+       String[] gTokens = t.getTokens();
+       int len = tokens.length;
+       int glen = gTokens.length;
+       if(len == 0 || glen == 0)
+           return 0;
+       for(int i=0; i<Math.min(len, glen); i++){
+           if(tokens[i].equalsIgnoreCase(gTokens[i]))
+               continue;
+           if(tokens[i].equals(WILD) || gTokens[i].equals(WILD))
+               continue;
+           return 0;
+       }
+       return Math.min(len,glen);
+    }
+    
+    public String toString(){
+       StringBuffer buf = new StringBuffer();
+       int len =tokens.length;
+       for(int i = 0; i < len-1; i++){
+           buf.append(tokens[i]);
+           buf.append(", ");
+       }
+       if(len > 0)
+           buf.append(tokens[len-1]); // add the last one
+       return buf.toString();
+    }
+} /* end class TName */
diff --git a/src/edu/internet2/middleware/shibboleth/aa/makefile b/src/edu/internet2/middleware/shibboleth/aa/makefile
new file mode 100755 (executable)
index 0000000..8c8c052
--- /dev/null
@@ -0,0 +1,19 @@
+CP=.:/afs/andrew/acs/asg/shibboleth/runtime/java/v2/lib/xercesImpl.jar:/afs/andrew/acs/asg/shibboleth/runtime/java/v2/lib/xmlParserAPIs.jar:/afs/andrew/acs/asg/shibboleth/runtime/java/v2/lib/shibboleth.jar:/afs/andrew/acs/asg/shibboleth/runtime/java/v2/lib/opensaml.jar:/usr/www/tomcat/lib/servlet.jar:/usr/java/jre/lib/rt.jar:../../lib/jndi.jar
+
+INSTDIR=/afs/andrew/acs/asg/shibboleth/cmu/beta/lib
+
+all:
+       javac -g -classpath ${CP} *.java
+
+docs:
+       javadoc -classpath ${CP} -d /usr/www/tree/aa *java
+
+jar:   all
+       mkdir aa;
+       cp *.class aa;
+       jar -cvf aa.jar aa;
+       rm -fr aa
+
+install:  jar
+       cp aa.jar ${INSTDIR}
+