From 2d0aba220afc66dcb50fcd2639df306a25f639ea Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Wed, 02 May 2007 02:02:04 +0000
Subject: [PATCH] Add ACI support for Get Effective Rights control. Issue #87.

---
 opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java |  538 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 408 insertions(+), 130 deletions(-)

diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index 2602242..495212b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -32,11 +32,18 @@
 import org.opends.server.api.Group;
 import org.opends.server.api.ConnectionSecurityProvider;
 import org.opends.server.core.AddOperation;
+import org.opends.server.core.SearchOperation;
 import org.opends.server.extensions.TLSConnectionSecurityProvider;
 import org.opends.server.types.Operation;
 import java.net.InetAddress;
 import java.util.LinkedList;
+import java.util.List;
+import java.util.HashMap;
+
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.authorization.dseecompat.AciHandler.*;
+import org.opends.server.controls.GetEffectiveRights;
+import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
 
 /**
  *  The AciContainer class contains all of the needed information to perform
@@ -94,6 +101,7 @@
      * The entry being evaluated (resource entry).
      */
     private Entry resourceEntry;
+    private Entry saveResourceEntry;
 
     /*
      * The client connection information.
@@ -145,12 +153,86 @@
      */
     private boolean seenEntry=false;
 
-    /**
+    /*
+     *  True if geteffectiverights evaluation is in progress.
+     */
+    private boolean isGetEffectiveRightsEval=false;
+
+     /*
+     *  True if the operation has a geteffectiverights control.
+     */
+    private boolean hasGetEffectiveRightsControl=false;
+
+    /*
+     * The geteffectiverights authzID in DN format.
+     */
+    private DN authzid=null;
+
+    /*
+     * True if the authZid should be used as the client DN, only used in
+     * geteffectiverights evaluation.
+     */
+    private boolean useAuthzid=false;
+
+    /*
+     * The list of specific attributes to get rights for, in addition to
+     * any attributes requested in the search.
+     */
+    private List<AttributeType> specificAttrs=null;
+
+    /*
+     * The entry with all of its attributes available. Used in
+     * geteffectiverights read entry level evaluation.
+     */
+    private Entry fullEntry=null;
+
+    /*
+     * Table of ACIs that have targattrfilter keywords that matched. Used
+     * in geteffectiverights attributeLevel write evaluation.
+     */
+    private HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
+
+    /*
+     * The name of a ACI that decided an evaluation and contained a
+     * targattrfilter keyword. Used in geteffectiverights attributeLevel
+     * write evaluation.
+     */
+    private String targAttrFiltersAciName=null;
+
+    /*
+     * Value that is used to store the allow/deny result of a deciding ACI
+     * containing a targattrfilter keyword.  Used in geteffectiverights
+     * attributeLevel write evaluation.
+     */
+    private int targAttrMatch=0;
+
+    /*
+     * The ACI that decided the last evaluation. Used in geteffectiverights
+     * loginfo processing.
+     */
+    private Aci decidingAci=null;
+
+    /*
+     * The reason the last evaluation decision was made. Used both
+     * in geteffectiverights loginfo processing and attributeLevel write
+     * evaluation.
+     */
+    private EnumEvalReason evalReason=null;
+
+    /*
+     * A summary string holding the last evaluation information in textual
+     * format. Used in geteffectiverights loginfo processing.
+     */
+    private String summaryString=null;
+
+  /**
      * This constructor is used by all currently supported LDAP operations.
      *
      * @param operation The Operation object being evaluated and target
      * matching.
+     *
      * @param rights The rights array to use in evaluation and target matching.
+     *
      * @param entry The current entry being evaluated and target matched.
      */
     protected AciContainer(Operation operation, int rights, Entry entry) {
@@ -167,16 +249,34 @@
       if(origAuthorizationEntry != null)
          this.proxiedAuthorization=true;
       this.authorizationEntry=operation.getAuthorizationEntry();
-
+      //Only need to process the geteffectiverights control once, -- for a
+      //SearchOperation with read right. It is saved in the operation
+      //attachment after that.
+      if(operation instanceof SearchOperation && (rights == ACI_READ)) {
+        GetEffectiveRights getEffectiveRightsControl =
+              (GetEffectiveRights)
+                      operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS);
+        if(getEffectiveRightsControl != null) {
+          hasGetEffectiveRightsControl=true;
+          if(getEffectiveRightsControl.getAuthzDN() == null)
+            this.authzid=getClientDN();
+          else
+            this.authzid=getEffectiveRightsControl.getAuthzDN();
+          this.specificAttrs=getEffectiveRightsControl.getAttributes();
+          fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
+        }
+      }
       //Reference the current authorization entry, so it can be put back
       //if an access proxy check was performed.
       this.saveAuthorizationEntry=this.authorizationEntry;
+      this.saveResourceEntry=this.resourceEntry;
       this.rights = rights;
     }
 
   /**
    * Returns true if an entry has already been processed by an access proxy
    * check.
+   *
    * @return True if an entry has already been processed by an access proxy
    * check.
    */
@@ -187,6 +287,7 @@
   /**
    * Set to true if an entry has already been processsed by an access proxy
    * check.
+   *
    * @param val The value to set the seenEntry boolean to.
    */
     public void setSeenEntry(boolean val) {
@@ -194,14 +295,200 @@
     }
 
   /**
-   * Returns true if proxied authorization is being used.
-   * @return  True if proxied authorization is being used.
+   * {@inheritDoc}
    */
     public boolean isProxiedAuthorization() {
          return this.proxiedAuthorization;
     }
 
   /**
+   * {@inheritDoc}
+   */
+    public boolean isGetEffectiveRightsEval() {
+        return this.isGetEffectiveRightsEval;
+    }
+
+  /**
+   * The container is going to be used in a geteffectiverights evaluation, set
+   * the flag isGetEffectiveRightsEval to true.
+   */
+  public void setGetEffectiveRightsEval() {
+       this.isGetEffectiveRightsEval=true;
+    }
+
+  /**
+   * Return true if the container is being used in a geteffectiverights
+   * evaluation.
+   *
+   * @return True if the container is being used in a geteffectiverights
+   * evaluation.
+   */
+    public boolean hasGetEffectiveRightsControl() {
+      return this.hasGetEffectiveRightsControl;
+    }
+
+  /**
+   * Use the DN from the geteffectiverights control's authzId as the
+   * client DN, rather than the authorization entry's DN.
+   *
+   * @param v The valued to set the useAuthzid to.
+   */
+    public void useAuthzid(boolean v) {
+       this.useAuthzid=v;
+    }
+
+  /**
+   * Return the list of additional attributes specified in the
+   * geteffectiveritghts control.
+   *
+   * @return The list of attributes to return rights information about in the
+   * entry.
+   */
+    public List<AttributeType> getSpecificAttributes() {
+       return this.specificAttrs;
+    }
+
+  /**
+   * During the geteffectiverights entrylevel read evaluation, an entry with all
+   * of the attributes used in the AciHandler's maysend method evaluation is
+   * needed to perform the evaluation over again. This entry was saved
+   * in the operation's attachment mechanism when the container was created
+   * during the SearchOperation read evaluation.
+   *
+   * This method is used to replace the current resource entry with that saved
+   * entry to perform the entrylevel read evaluation described above and to
+   * switch back to the current resource entry when needed.
+   *
+   * @param val Specifies if the saved entry should be used or not. True if it
+   * should be used, false if the original resource entry should be used.
+   *
+   */
+    public void useFullResourceEntry(boolean val) {
+      if(val)
+        resourceEntry=fullEntry;
+      else
+        resourceEntry=saveResourceEntry;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void addTargAttrFiltersMatchAci(Aci aci) {
+      this.targAttrFilterAcis.put(aci, aci);
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public boolean hasTargAttrFiltersMatchAci(Aci aci) {
+      return this.targAttrFilterAcis.containsKey(aci);
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public boolean isTargAttrFilterMatchAciEmpty() {
+       return this.targAttrFilterAcis.isEmpty();
+    }
+
+  /**
+   * Reset the values used by the geteffectiverights evaluation to
+   * original values. The geteffectiverights evaluation uses the same container
+   * repeatedly for different rights evaluations (read, write, proxy,...) and
+   * this method resets variables that are specific to a single evaluation.
+   */
+    public void resetEffectiveRightsParams() {
+      this.targAttrFilterAcis.clear();
+      this.decidingAci=null;
+      this.evalReason=null;
+      this.targAttrFiltersMatch=false;
+      this.summaryString=null;
+      this.targAttrMatch=0;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void setTargAttrFiltersAciName(String name) {
+      this.targAttrFiltersAciName=name;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public String getTargAttrFiltersAciName() {
+      return this.targAttrFiltersAciName;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void setTargAttrFiltersMatchOp(int flag) {
+      this.targAttrMatch |= flag;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public boolean hasTargAttrFiltersMatchOp(int flag) {
+       return (this.targAttrMatch & flag) != 0;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void setDecidingAci(Aci aci) {
+      this.decidingAci=aci;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public String getDecidingAciName() {
+      if(this.decidingAci != null)
+         return this.decidingAci.getName();
+      else return null;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void setEvalReason(EnumEvalReason reason) {
+      this.evalReason=reason;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public EnumEvalReason getEvalReason() {
+      return this.evalReason;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+    public void setEvalSummary(String summary) {
+      this.summaryString=summary;
+    }
+
+   /**
+    * {@inheritDoc}
+    */
+     public String getEvalSummary() {
+      return this.summaryString;
+    }
+
+  /**
+   * Returns true if the geteffectiverights control's authZid DN is equal to the
+   * authoritzation entry's DN.
+   *
+   * @return True if the authZid is equal to the authorization entry's DN.
+   */
+    public boolean isAuthzidAuthorizationDN() {
+     return this.authzid.equals(this.authorizationEntry.getDN());
+    }
+
+  /**
    * If the specified value is true, then the original authorization entry,
    * which is the  entry before the switch performed by the proxied
    * authorization control processing should be set to the current
@@ -216,228 +503,194 @@
         authorizationEntry=saveAuthorizationEntry;
     }
 
-    /**
-     * The list of deny ACIs. These are all of the applicable
-     * ACIs that have a deny permission. Note that an ACI can
-     * be on both allow and deny list if it has multiple
-     * permission-bind rule pairs.
-     *
-     * @param denys The list of deny ACIs.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setDenyList(LinkedList<Aci> denys) {
         denyList=denys;
     }
 
-    /**
-     * The list of allow ACIs. These are all of the applicable
-     * ACIs that have an allow permission.
-     *
-     * @param allows  The list of allow ACIs.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setAllowList(LinkedList<Aci> allows) {
         allowList=allows;
     }
 
-    /**
-     * Return the current attribute type being evaluated.
-     * @return  Attribute type being evaluated.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public AttributeType getCurrentAttributeType() {
         return attributeType;
     }
 
-    /**
-     * Return the current attribute type value being evaluated.
-     * @return Attribute type value being evaluated.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public AttributeValue getCurrentAttributeValue() {
         return attributeValue;
     }
 
-    /**
-     * Set the attribute type to be evaluated.
-     * @param type The attribute type to evaluate.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setCurrentAttributeType(AttributeType type) {
         attributeType=type;
     }
 
-    /**
-     * Set the attribute type value to be evaluated.
-     * @param value The attribute type value to evaluate.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setCurrentAttributeValue(AttributeValue value) {
         attributeValue=value;
     }
 
-    /**
-     * Check is this the first attribute being evaluated in an entry.
-     * @return  True if it is the first attribute.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean isFirstAttribute() {
         return isFirst;
     }
 
-    /**
-     * Set if this is the first attribute in the entry.
-     * @param val True if this is the first attribute being evaluated in the
-     * entry.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setIsFirstAttribute(boolean val) {
         isFirst=val;
     }
 
-    /**
-     * Check if an entry test rule was seen during target evaluation.
-     * @return True if an entry test rule was seen.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean hasEntryTestRule() {
         return isEntryTestRule;
     }
 
-    /**
-     * Used to set if an entry test rule was seen during target evaluation.
-     * @param val Set to true if an entry test rule was seen.
-     */
-    public void setEntryTestRule(boolean val) {
+   /**
+    * {@inheritDoc}
+    */
+   public void setEntryTestRule(boolean val) {
         isEntryTestRule=val;
     }
 
-    /**
-     * Get the entry being evaluated (known as the resource entry).
-     * @return  The entry being evaluated.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public Entry getResourceEntry() {
         return resourceEntry;
     }
 
-    /**
-     * Get the entry that corresponds to the client DN.
-     * @return The client entry.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public Entry getClientEntry() {
       return this.authorizationEntry;
     }
 
-    /**
-     * Get the deny list of ACIs.
-     * @return The deny ACI list.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public LinkedList<Aci> getDenyList() {
         return denyList;
      }
 
-    /**
-     * Get the allow list of ACIs.
-     * @return The allow ACI list.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public LinkedList<Aci> getAllowList() {
        return allowList;
     }
 
-    /**
-     * Check is this is a deny ACI evaluation.
-     * @return  True if the evaluation is using an ACI from
-     * deny list.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean isDenyEval() {
         return isDenyEval;
     }
 
-    /**
-     * Check is this operation bound anonymously.
-     * @return  True if the authentication is anonymous.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean isAnonymousUser() {
         return !clientConnection.getAuthenticationInfo().isAuthenticated();
     }
 
-    /**
-     * Set the deny evaluation flag.
-     * @param val True if this evaluation is a deny ACI.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setDenyEval(boolean val) {
         isDenyEval = val;
     }
 
-    /**
-     * Returns the client authorization DN known as the client DN.
-     * @return  The client's authorization DN.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public DN getClientDN() {
-      return this.authorizationEntry.getDN();
+      if(this.useAuthzid)
+        return this.authzid;
+      else
+       return this.authorizationEntry.getDN();
     }
 
-    /**
-     * Get the DN of the entry being evaluated.
-     * @return The DN of the entry.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public DN getResourceDN() {
         return resourceEntry.getDN();
     }
 
-    /**
-     * Checks if the container's rights has the specified rights.
-     * @param  rights The rights to check for.
-     * @return True if the container's rights has the specified rights.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean hasRights(int rights) {
        return (this.rights & rights) != 0;
     }
 
-    /**
-     * Return the rights set for this container's LDAP operation.
-     * @return  The rights set for the container's LDAP operation.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public int getRights() {
         return this.rights;
     }
 
-    /**
-     * Sets the rights for this container to the specified rights.
-     * @param rights The rights to set the container's rights to.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setRights(int rights) {
          this.rights=rights;
     }
 
-    /**
-     * Gets the hostname of the remote client.
-     * @return  Cannonical hostname of remote client.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public String getHostName() {
         return clientConnection.getRemoteAddress().getCanonicalHostName();
     }
 
-    /**
-     * Gets the remote client's address information.
-     * @return  Remote client's address.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public InetAddress getRemoteAddress() {
         return clientConnection.getRemoteAddress();
     }
 
-    /**
-     * Return true if the current operation is a LDAP add operation.
-     * @return True if this is an add operation.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean isAddOperation() {
         return isAddOp;
     }
 
-    /**
-     * Set to true  if the ACI had a targattrfilter rule that matched.
-     * @param v  The value to use.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public void setTargAttrFiltersMatch(boolean v) {
         this.targAttrFiltersMatch=v;
     }
 
-    /**
-     * Return the value of the targAttrFiltersMatch variable. This is set to
-     * true if the ACI had a targattrfilter rule that matched.
-     * @return  True if the ACI had a targattrfilter rule that matched.
-     */
+   /**
+    * {@inheritDoc}
+    */
     public boolean getTargAttrFiltersMatch() {
         return targAttrFiltersMatch;
     }
@@ -498,12 +751,9 @@
       return matched;
     }
 
-    /**
-     * Convenience method that checks if the the clientDN is a member of the
-     * specified group.
-     * @param group The group to check membership in.
-     * @return True if the clientDN is a member of the specified group.
-     */
+  /**
+   * {@inheritDoc}
+   */
     public boolean isMemberOf(Group group) {
         boolean ret;
         try {
@@ -513,4 +763,32 @@
         }
         return  ret;
     }
+
+  /**
+   * {@inheritDoc}
+   */
+    public String rightToString() {
+      if(hasRights(ACI_SEARCH))
+        return "search";
+      else if(hasRights(ACI_COMPARE))
+        return "compare";
+      else if(hasRights(ACI_READ))
+        return "read";
+      else if(hasRights(ACI_DELETE))
+        return "delete";
+      else if(hasRights(ACI_ADD))
+        return "add";
+      else if(hasRights(ACI_WRITE))
+        return "write";
+      else if(hasRights(ACI_PROXY))
+        return "proxy";
+      else if(hasRights(ACI_IMPORT))
+        return "import";
+      else if(hasRights(ACI_EXPORT))
+        return "export";
+      else if(hasRights(ACI_WRITE) &&
+              hasRights(ACI_SELF))
+        return "selfwrite";
+      return null;
+  }
 }

--
Gitblit v1.10.0