From 10d7c1ea90c6016ab1e6cc2218c44dcb74a5fdb3 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Tue, 10 Apr 2007 21:02:22 +0000
Subject: [PATCH] Add ACI support for proxy right. Issue #1489.

---
 opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java                                      |   20 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                              |    2 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                       |   82 +++++++-
 opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java                   |   18 +
 opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java                                      |   21 ++
 opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java                                         |   20 ++
 opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java                                     |   20 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java |  185 ++++++++++++++++-
 opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java                         |    9 
 opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java                                    |   21 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                     |   94 +++++++++
 opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java                                  |   29 ++
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java                                      |   21 ++
 13 files changed, 493 insertions(+), 49 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
index fccc56c..eec0fac 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -28,17 +28,10 @@
 
 
 
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.BindOperation;
-import org.opends.server.core.CompareOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.ExtendedOperation;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.core.*;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
-
+import org.opends.server.types.Entry;
 
 
 /**
@@ -237,5 +230,23 @@
    */
   public abstract boolean maySend(SearchOperation searchOperation,
                                SearchResultReference searchReference);
+
+  /**
+   * Indicates whether a proxied authorization control is allowed
+   * based on the current operation and the new authorization
+   * entry.
+   *
+   * @param operation
+   *        The operation with which the proxied authorization
+   *        control is associated.
+   * @param newAuthorizationEntry
+   *        The new authorization entry related to the
+   *        proxied authorization control authorization ID.
+   * @return  <CODE>true</CODE> if the operation should be allowed by
+   *         the access control configuration, or <CODE>false</CODE>
+   *         if not.
+   */
+  public abstract boolean isProxiedAuthAllowed(Operation operation,
+                                        Entry newAuthorizationEntry);
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
index 4e4c71a..756c8e0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/BasicAccessControlHandler.java
@@ -28,16 +28,10 @@
 
 
 import org.opends.server.api.AccessControlHandler;
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.BindOperation;
-import org.opends.server.core.CompareOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.ExtendedOperation;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.core.*;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.Entry;
 
 /**
  * This class provides the implementation of the basic access control
@@ -169,4 +163,12 @@
 
     return true;
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+     return true;
+  }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index 5308889..2d6869a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -194,7 +194,7 @@
     public static final int ACI_ALL = 0x007F;
 
     /**
-     * ACI_PROXY is used for the PROXY right. Currently not used.
+     * ACI_PROXY is used for the PROXY right.
      */
     public static final int ACI_PROXY = 0x0080;
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index baea9bd..c4ac14c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -36,6 +36,7 @@
 import org.opends.server.extensions.TLSConnectionSecurityProvider;
 import java.net.InetAddress;
 import java.util.LinkedList;
+import static org.opends.server.authorization.dseecompat.AciHandler.*;
 
 /**
  *  The AciContainer class contains all of the needed information to perform
@@ -109,6 +110,41 @@
      */
     private boolean targAttrFiltersMatch=false;
 
+    /*
+     * The authorization entry currently being evaluated. If proxied
+     * authorization is being used and the handler is doing a proxy access
+     * check, then this entry will switched to the original authorization entry
+     * rather than the proxy ID entry. If the check succeeds, it will be
+     * switched back for non-proxy access checking. If proxied authentication
+     * is not being used then this entry never changes.
+     */
+    private Entry authorizationEntry;
+
+    /*
+     * Used to save the current authorization entry when the authorization
+     * entry is switched during a proxy access check.
+     */
+    private Entry saveAuthorizationEntry;
+
+    /*
+     * This entry is only used if proxied authorization is being used.  It is
+     * the original authorization entry before the proxied authorization change.
+     */
+    private Entry origAuthorizationEntry=null;
+
+    /*
+     * True if proxied authorization is being used.
+     */
+    private boolean proxiedAuthorization=false;
+
+    /*
+     * Used by proxied authorization processing. True if the entry has already
+     * been processed by an access proxy check. Some operations might perform
+     * several access checks on the same entry (modify DN), this
+     * flag is used to bypass the proxy check after the initial evaluation.
+     */
+    private boolean seenEntry=false;
+
     /**
      * This constructor is used by all currently supported LDAP operations.
      *
@@ -123,9 +159,63 @@
       this.clientConnection=operation.getClientConnection();
       if(operation instanceof AddOperation)
           this.isAddOp=true;
+
+      //If the proxied authorization control was processed, then the operation
+      //will contain an attachment containing the original authorization entry.
+      this.origAuthorizationEntry =
+                      (Entry) operation.getAttachment(ORIG_AUTH_ENTRY);
+      if(origAuthorizationEntry != null)
+         this.proxiedAuthorization=true;
+      this.authorizationEntry=operation.getAuthorizationEntry();
+
+      //Reference the current authorization entry, so it can be put back
+      //if an access proxy check was performed.
+      this.saveAuthorizationEntry=this.authorizationEntry;
       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.
+   */
+   public boolean hasSeenEntry() {
+      return this.seenEntry;
+    }
+
+  /**
+   * 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) {
+     this.seenEntry=val;
+    }
+
+  /**
+   * Returns true if proxied authorization is being used.
+   * @return  True if proxied authorization is being used.
+   */
+    public boolean isProxiedAuthorization() {
+         return this.proxiedAuthorization;
+    }
+
+  /**
+   * 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
+   * authorization entry. If the specified value is false then the proxied
+   * authorization entry is switched back using the saved copy.
+   * @param val The value used to select the authorization entry to use.
+   */
+    public void useOrigAuthorizationEntry(boolean val) {
+      if(val)
+        authorizationEntry=origAuthorizationEntry;
+      else
+        authorizationEntry=saveAuthorizationEntry;
+    }
+
     /**
      * The list of deny ACIs. These are all of the applicable
      * ACIs that have a deny permission. Note that an ACI can
@@ -226,7 +316,7 @@
      * @return The client entry.
      */
     public Entry getClientEntry() {
-      return operation.getAuthorizationEntry();
+      return this.authorizationEntry;
     }
 
     /**
@@ -275,7 +365,7 @@
      * @return  The client's authorization DN.
      */
     public DN getClientDN() {
-      return operation.getAuthorizationDN();
+      return this.authorizationEntry.getDN();
     }
 
     /**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 8544649..ea636bc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -72,6 +72,12 @@
     public static AttributeType globalAciType;
 
     /**
+     * String used to save the original authorization entry in an operation
+     * attachment if a proxied authorization control was seen.
+     */
+    public static String ORIG_AUTH_ENTRY="origAuthorizationEntry";
+
+    /**
      * This constructor instantiates the ACI handler class that performs the
      * main processing for the dseecompat ACI package. It does the following
      * initializations:
@@ -443,6 +449,32 @@
              return false;
           }
         }
+
+        //Check proxy authorization only if the entry has not already been
+        //processed (working on a new entry). If working on a new entry, then
+        //only do a proxy check if the right is not set to ACI_PROXY and the
+        //proxied authorization control has been decoded.
+        if(!container.hasSeenEntry()) {
+          if(!container.hasRights(ACI_PROXY) &&
+             container.isProxiedAuthorization()) {
+              int currentRights=container.getRights();
+              //Save the current rights so they can be put back if on success.
+              container.setRights(ACI_PROXY);
+              //Switch to the original authorization entry, not the proxied one.
+              container.useOrigAuthorizationEntry(true);
+              if(!accessAllowed(container))
+                  return false;
+              //Access is ok, put the original rights back.
+              container.setRights(currentRights);
+              //Put the proxied authorization entry back to the current
+              //authorization entry.
+              container.useOrigAuthorizationEntry(false);
+          }
+          //Set the seen flag so proxy processing is not performed for this
+          //entry again.
+          container.setSeenEntry(true);
+       }
+
         /*
          * First get all allowed candidate ACIs.
          */
@@ -714,7 +746,6 @@
      * @return  True if access is allowed.
      */
    public boolean isAllowed(CompareOperation operation) {
-
        AciLDAPOperationContainer operationContainer =
                new AciLDAPOperationContainer(operation, ACI_COMPARE);
        String baseName;
@@ -803,10 +834,12 @@
    */
   public SearchResultEntry filterEntry(SearchOperation operation,
                                        SearchResultEntry entry) {
-
       AciLDAPOperationContainer operationContainer =
               new AciLDAPOperationContainer(operation,
                                             (ACI_READ), entry);
+      //Proxy access check has already been done for this entry in the maySend
+      //method, set the seen flag to true to bypass any proxy check.
+      operationContainer.setSeenEntry(true);
       SearchResultEntry returnEntry;
       if(!skipAccessCheck(operation)) {
           returnEntry=accessAllowedAttrs(operationContainer);
@@ -816,10 +849,10 @@
   }
 
   /**
-   * Perform all needed RDN checks for the modifyDN operation. These checks
-   * are:
+   * Perform all needed RDN checks for the modifyDN operation. The old RDN is
+   * not equal to the new RDN. The access checks are:
    *
-   *  - Verify WRITE access to the entry.
+   *  - Verify WRITE access to the original entry.
    *  - Verfiy WRITE_ADD access on each RDN component of the new RDN. The
    *    WRITE_ADD access is used because this access could be restricted by
    *    the targattrfilters keyword.
@@ -829,18 +862,21 @@
    *
    * @param operation   The ModifyDN operation class containing information to
    * check access on.
+   * @param oldRDN      The old RDN component.
+   * @param newRDN      The new RDN component.
    * @return True if access is allowed.
    */
-  private boolean aciCheckRDNs(ModifyDNOperation operation) {
+  private boolean aciCheckRDNs(ModifyDNOperation operation, RDN oldRDN,
+                               RDN newRDN) {
       boolean ret;
+
       AciLDAPOperationContainer operationContainer =
               new AciLDAPOperationContainer(operation, (ACI_WRITE),
                       operation.getOriginalEntry());
       ret=accessAllowed(operationContainer);
       if(ret)
-          ret=checkRDN(ACI_WRITE_ADD,operation.getNewRDN(),operationContainer);
+          ret=checkRDN(ACI_WRITE_ADD, newRDN, operationContainer);
       if(ret && operation.deleteOldRDN()) {
-          RDN oldRDN=operation.getOriginalEntry().getDN().getRDN();
           ret =
             checkRDN(ACI_WRITE_DELETE, oldRDN, operationContainer);
       }
@@ -923,6 +959,8 @@
   public boolean isAllowed(ModifyDNOperation operation) {
       boolean ret=true;
       DN newSuperiorDN;
+      RDN oldRDN=operation.getOriginalEntry().getDN().getRDN();
+      RDN newRDN=operation.getNewRDN();
       if(!skipAccessCheck(operation)) {
           //If this is a modifyDN move to a new superior, then check if the
           //superior DN has import accesss.
@@ -933,21 +971,41 @@
                ret=false;
              }
           }
-          //Perform the RDN access checks.
-          if(ret)
-              ret=aciCheckRDNs(operation);
+          boolean rdnEquals=oldRDN.equals(newRDN);
+          //Perform the RDN access checks only if the RDNs are not equal.
+          if(ret && !rdnEquals)
+              ret=aciCheckRDNs(operation, oldRDN, newRDN);
+
           //If this is a modifyDN move to a new superior, then check if the
           //original entry DN has export access.
           if(ret && (newSuperiorDN != null)) {
               AciLDAPOperationContainer operationContainer =
                       new AciLDAPOperationContainer(operation, (ACI_EXPORT),
-                              operation.getOriginalEntry());
+                                             operation.getOriginalEntry());
+                 //The RDNs are not equal, skip the proxy check since it was
+                 //already performed in the aciCheckRDNs call above.
+                 if(!rdnEquals)
+                     operationContainer.setSeenEntry(true);
                  ret=accessAllowed(operationContainer);
           }
       }
       return ret;
   }
 
+  //TODO Check access to control, issue #452.
+  /**
+   * Called when a proxied authorization control was decoded. Currently used
+   * to save the current authorization entry in an operation attachment, but
+   * eventually will be used to check access to the actual control.
+   * @param operation The operation to save the attachment to.
+   * @param entry  The new authorization entry.
+   * @return  True if the control is allowed access.
+   */
+  public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+    operation.setAttachment(ORIG_AUTH_ENTRY, operation.getAuthorizationEntry());
+    return true;
+  }
+
   //Not planned to be implemented methods.
 
    /**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
index ef72f64..e5f77dd 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/AddOperation.java
@@ -1767,7 +1767,17 @@
                 break addProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break addProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
             else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1827,7 +1837,17 @@
                 break addProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break addProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
index ff1843b..09a6f16 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
@@ -824,7 +824,17 @@
                 break compareProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                 authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break compareProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
             else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -884,7 +894,17 @@
                 break compareProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                 authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break compareProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
index 9bccfd3..612890e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlProvider.java
@@ -33,6 +33,7 @@
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.Entry;
 
 /**
  * This class implements a default access control provider for the
@@ -197,5 +198,13 @@
 
       return true;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
+     return true;
+    }
   }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
index 32ac395..906aa35 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DeleteOperation.java
@@ -817,7 +817,17 @@
                 break deleteProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break deleteProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
             else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -876,7 +886,17 @@
 
                 break deleteProcessing;
               }
+              if (AccessControlConfigManager.getInstance()
+                  .getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break deleteProcessing;
+              }
 
               setAuthorizationEntry(authorizationEntry);
             }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
index 3b58b7d..0fefd47 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -1277,7 +1277,17 @@
                 break modifyDNProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance()
+                      .getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break modifyDNProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
             else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1336,6 +1346,17 @@
 
                 break modifyDNProcessing;
               }
+              if (AccessControlConfigManager.getInstance()
+                  .getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break modifyDNProcessing;
+              }
 
 
               setAuthorizationEntry(authorizationEntry);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
index 1c9ea1d..58cb53b 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -101,6 +101,7 @@
 import static org.opends.server.loggers.Error.*;
 import static org.opends.server.messages.CoreMessages.*;
 import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
@@ -1080,7 +1081,17 @@
 
                 break modifyProcessing;
               }
+              if (AccessControlConfigManager.getInstance().
+                      getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break modifyProcessing;
+              }
 
               setAuthorizationEntry(authorizationEntry);
             }
@@ -1141,7 +1152,17 @@
                 break modifyProcessing;
               }
 
+              if (AccessControlConfigManager.getInstance().
+                      getAccessControlHandler().isProxiedAuthAllowed(this,
+                      authorizationEntry) == false) {
+                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
+
+                skipPostOperation = true;
+                break modifyProcessing;
+              }
               setAuthorizationEntry(authorizationEntry);
             }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
index 7d4f2f7..d4c3d49 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
@@ -1758,7 +1758,17 @@
               break searchProcessing;
             }
 
+            if (AccessControlConfigManager.getInstance().
+                 getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                 authorizationEntry) == false) {
+              setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
 
+              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+              appendErrorMessage(getMessage(msgID, String.valueOf(baseDN)));
+
+              skipPostOperation = true;
+              break searchProcessing;
+            }
             setAuthorizationEntry(authorizationEntry);
           }
           else if (oid.equals(OID_PROXIED_AUTH_V2))
@@ -1818,6 +1828,17 @@
               break searchProcessing;
             }
 
+            if (AccessControlConfigManager.getInstance()
+                .getAccessControlHandler().isProxiedAuthAllowed(this,
+                                                 authorizationEntry) == false) {
+              setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+              appendErrorMessage(getMessage(msgID, String.valueOf(baseDN)));
+
+              skipPostOperation = true;
+              break searchProcessing;
+            }
 
             setAuthorizationEntry(authorizationEntry);
           }
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
index 7948766..5028fd7 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -182,6 +182,8 @@
   private static final String LEVEL_1_USER_DN = "cn=level1 user," + OU_BASE_DN;
   private static final String LEVEL_2_USER_DN = "cn=level2 user," + OU_INNER_DN;
   private static final String LEVEL_3_USER_DN = "cn=level3 user," + OU_LEAF_DN;
+  //The proxy DN.
+  private static final String PROXY_USER_DN = "cn=proxy user," + OU_BASE_DN;
 
   // We need to delete all of these between each test.  This list needs to be
   // bottom up so that it can be handed to LDAPDelete.
@@ -189,6 +191,7 @@
     SALES_USER_1,
     SALES_USER_2,
     SALES_USER_3,
+    PROXY_USER_DN,
     LEVEL_3_USER_DN,
     LEVEL_2_USER_DN,
     LEVEL_1_USER_DN,
@@ -209,6 +212,10 @@
   private static final String BIND_RULE_USERDN_ALL = "userdn=\"ldap:///all\"";
   private static final String BIND_RULE_USERDN_ADMIN = "userdn=\"ldap:///" + ADMIN_DN + "\"";
   private static final String BIND_RULE_USERDN_LEVEL_1 = "userdn=\"ldap:///" + LEVEL_1_USER_DN + "\"";
+  //The proxy userdn bind rule.
+  private static final String BIND_RULE_USERDN_PROXY =
+                                     "userdn=\"ldap:///" + PROXY_USER_DN + "\"";
+
   private static final String BIND_RULE_USERDN_ANYONE = "userdn=\"ldap:///anyone\"";
   private static final String BIND_RULE_USERDN_PARENT = "userdn=\"ldap:///parent\"";
   private static final String BIND_RULE_USERDN_CN_RDN = "userdn=\"ldap:///CN=*,dc=example,dc=com\"";
@@ -306,6 +313,36 @@
   private static final String ALLOW_ALL_TO_COMPARE =
              buildAciValue("name", "allow compare", "targetattr", "*", "target", "ldap:///cn=*," + OU_LEAF_DN, "allow(compare)", BIND_RULE_USERDN_ALL);
 
+  //The ACIs for the proxy tests.
+
+  private static final String ALLOW_PROXY_TO_IMPORT_MGR_NEW =
+          buildAciValue("name", "allow proxy import new mgr new tree", "target",
+                     MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_PROXY);
+
+  private static final String ALLOW_PROXY_TO_IMPORT_MGR=
+             buildAciValue("name", "allow proxy import mgr tree", "target",
+                     MGR_DN_URL, "allow(import)", BIND_RULE_USERDN_PROXY);
+
+  private static final String ALLOW_PROXY_TO_EXPORT_MGR_NEW =
+          buildAciValue("name", "allow proxy export new mgr new tree", "target",
+                     MGR_NEW_DN_URL, "allow(export)", BIND_RULE_USERDN_PROXY);
+
+  private static final String ALLOW_PROXY_TO_EXPORT_MGR=
+             buildAciValue("name", "allow proxy export mgr tree", "target",
+                     MGR_DN_URL, "allow(export)", BIND_RULE_USERDN_PROXY);
+
+  private static final String ALLOW_PROXY_TO_WRITE_RDN_ATTRS=
+           buildAciValue("name", "allow proxy write to RDN attrs", "targetattr",
+                     "uid || cn || sn", "allow(write)", BIND_RULE_USERDN_PROXY);
+
+  private static final String ALLOW_PROXY_TO_MOVED_ENTRY =
+          buildAciValue("name", "allow proxy to moved entry", "targetattr", "*",
+                     "allow(search,read)", BIND_RULE_USERDN_PROXY);
+
+   private static final String ALLOW_PROXY_TO_LEVEL1 =
+          buildAciValue("name", "allow proxy to userdn level1", "targetattr", "*",
+                     "allow(proxy)", BIND_RULE_USERDN_LEVEL_1);
+
   private static final String ALLOW_ALL_TO_IMPORT_MGR_NEW =
              buildAciValue("name", "allow import mgr new tree", "target", MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL);
 
@@ -959,6 +996,8 @@
   private static final String LEVEL_1_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_1_USER_DN, "level1", "user", "pa$$word");
   private static final String LEVEL_2_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_2_USER_DN, "level2", "user", "pa$$word");
   private static final String LEVEL_3_USER_LDIF__SEARCH_TESTS = makeUserLdif(LEVEL_3_USER_DN, "level3", "user", "pa$$word");
+  private static final String PROXY_USER_LDIF__SEARCH_TESTS =
+                       makeUserLdif(PROXY_USER_DN, "proxy", "user", "pa$$word");
 
 
     private static final String SALES_USER_1__SEARCH_TESTS =
@@ -1050,7 +1089,7 @@
   String SELFWRITE_ACI =  makeAddAciLdif(OU_GROUP_1_DN,
                                         ALLOW_ALL_TO_SELFWRITE);
 
-  //ACIs used for modDN tests (export, import)
+  //ACIs used for standard modDN tests (export, import)
 
  private static final  String ACI_IMPORT_MGR_NEW =
                    makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_IMPORT_MGR_NEW);
@@ -1064,12 +1103,35 @@
  private static final  String ACI_EXPORT_MGR =
                    makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_EXPORT_MGR);
 
-  private static final String ACI_WRITE_RDN_ATTRS =
+ private static final String ACI_WRITE_RDN_ATTRS =
                    makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_WRITE_RDN_ATTRS);
 
-   private static final String ACI_MOVED_ENTRY =
+ private static final String ACI_MOVED_ENTRY =
                    makeAddAciLdif(SALES_USER_1, ALLOW_ALL_TO_MOVED_ENTRY);
 
+//ACIs used for proxied auth modDN tests
+
+  private static final  String ACI_PROXY_IMPORT_MGR_NEW =
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR_NEW);
+
+ private static final  String ACI_PROXY_IMPORT_MGR =
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR);
+
+ private static final  String ACI_PROXY_EXPORT_MGR_NEW =
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_EXPORT_MGR_NEW);
+
+ private static final  String ACI_PROXY_EXPORT_MGR =
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_EXPORT_MGR);
+
+ private static final String ACI_PROXY_WRITE_RDN_ATTRS =
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_WRITE_RDN_ATTRS);
+
+ private static final String ACI_PROXY_LEVEL_1=
+                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_LEVEL1);
+
+ private static final String ACI_PROXY_MOVED_ENTRY =
+                   makeAddAciLdif(SALES_USER_1, ALLOW_PROXY_TO_MOVED_ENTRY);
+
 //ACI used in testing the groupdn/roledn bind rule keywords.
 
  private static final
@@ -1116,6 +1178,7 @@
             GROUP_1_LDIF__SEARCH_TESTS +
             GROUP_2_LDIF__SEARCH_TESTS +
             LEVEL_1_USER_LDIF__SEARCH_TESTS +
+            PROXY_USER_LDIF__SEARCH_TESTS +
             INNER_OU_FULL_LDIF__SEARCH_TESTS;
 
   private static final String NO_ACIS_LDIF = "";
@@ -1484,6 +1547,7 @@
   private static class SingleSearchParams {
     private final String _bindDn;
     private final String _bindPw;
+    private final String _proxyDN;
     private final String _searchBaseDn;
     private final String _searchFilter;
     private final String _searchScope;
@@ -1491,9 +1555,25 @@
     private final String _initialDitLdif;
     private final String _aciLdif;
 
+    public SingleSearchParams(String bindDn, String bindPw, String proxyDN,
+                              String searchBaseDn, String searchFilter,
+                              String searchScope, String expectedResultsLdif,
+                              String initialDitLdif, String aciLdif) {
+      _bindDn = bindDn;
+      _bindPw = bindPw;
+      _proxyDN=proxyDN;
+      _searchBaseDn = searchBaseDn;
+      _searchFilter = searchFilter;
+      _searchScope = searchScope;
+      _expectedResultsLdif = expectedResultsLdif;
+      _initialDitLdif = initialDitLdif;
+      _aciLdif = aciLdif;
+    }
+
     public SingleSearchParams(String bindDn, String bindPw, String searchBaseDn, String searchFilter, String searchScope, String expectedResultsLdif, String initialDitLdif, String aciLdif) {
       _bindDn = bindDn;
       _bindPw = bindPw;
+      _proxyDN = null;
       _searchBaseDn = searchBaseDn;
       _searchFilter = searchFilter;
       _searchScope = searchScope;
@@ -1505,6 +1585,7 @@
     public SingleSearchParams(SingleSearchParams that, String initialDitLdif, String aciLdif) {
       _bindDn = that._bindDn;
       _bindPw = that._bindPw;
+      _proxyDN = null;
       _searchBaseDn = that._searchBaseDn;
       _searchFilter = that._searchFilter;
       _searchScope = that._searchScope;
@@ -1525,6 +1606,16 @@
           "-b", _searchBaseDn,
           "-s", _searchScope,
           _searchFilter};
+      } else if(_proxyDN != null) {
+        return new String[]{
+          "-h", "127.0.0.1",
+          "-p", getServerLdapPort(),
+          "-D", _bindDn,
+          "-w", _bindPw,
+          "-b", _searchBaseDn,
+          "-s", _searchScope,
+          "-Y", "dn:" + _proxyDN,
+          _searchFilter};
       } else {
         return new String[]{
           "-h", "127.0.0.1",
@@ -1659,6 +1750,58 @@
       }
   }
 
+
+  /**
+   * Test proxy keyword using modify DN. Exact test as testModDN, except using
+   * proxied authorization for modifies and searches.
+   *
+   * Add a set of ACIs to allow exports, imports and write rights to the
+   * proxy user PROXY_USER_DN. Also add an aci low in the DIT, with search and
+   * read rights to the proxy user. This is ACI is to test the
+   * ACI list after a move has been made. Add an ACI that allows LEVEL_1_USER_DN
+   * proxy authorization rights (proxy).
+   *
+   * Move the subtree binding as LEVEL_1_USER_DN using proxied authorization,
+   * search with base at new DN binding as LEVEL_1_USER_DN proxied
+   * authorization, then move the tree back binding as LEVEL_1_USER_DN using
+   * proxied authorization and lastly re-search with base at orig DN
+   * binding as LEVEL_1_USER_DN using proxied authorization.
+   * @throws Throwable
+   */
+  @Test
+  public void testProxyModDN() throws Throwable {
+    SingleSearchParams userParamOrig = new SingleSearchParams(LEVEL_1_USER_DN,
+                                      "pa$$word",PROXY_USER_DN, SALES_USER_1,
+                                      OBJECTCLASS_STAR, SCOPE_BASE,
+                                      null, null, null);
+    SingleSearchParams userParamNew = new SingleSearchParams(LEVEL_1_USER_DN,
+                                     "pa$$word",PROXY_USER_DN, SALES_USER_NEW_1,
+                                      OBJECTCLASS_STAR, SCOPE_BASE,
+                                      null, null, null);
+    try {
+      addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_IMPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_IMPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_EXPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_EXPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_WRITE_RDN_ATTRS, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_MOVED_ENTRY, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_LEVEL_1, DIR_MGR_DN, DIR_MGR_PW);
+      String modrdnLdif =
+              makeModDN(SALES_DN, "cn=sales dept", "0", MANAGER_NEW_DN);
+      modEntries(modrdnLdif, LEVEL_1_USER_DN, "pa$$word", PROXY_USER_DN);
+      String userNewResults = ldapSearch(userParamNew.getLdapSearchArgs());
+      Assert.assertFalse(userNewResults.equals(""));
+      String modrdnLdif1 =
+                makeModDN(SALES_NEW_DN, "cn=sales dept", "0", MANAGER_DN);
+      modEntries(modrdnLdif1, LEVEL_1_USER_DN, "pa$$word", PROXY_USER_DN);
+      String userOrigResults = ldapSearch(userParamOrig.getLdapSearchArgs());
+      Assert.assertFalse(userOrigResults.equals(""));
+    } catch (Throwable e)  {
+      throw e;
+    }
+  }
+
   /**
    * Test modify DN. Add a set of ACIs to allow exports, imports and write
    * rights. Also add an aci low in the DIT to test the ACI list after a move
@@ -1997,20 +2140,22 @@
     Assert.assertEquals(0, retVal,  "Non-zero return code because, error: " + getOutputStreamContents());
     return getOutputStreamContents();
   }
-  /**
-   *
-   */
+
   private void
   modEntries(String ldif, String bindDn, String bindPassword)
           throws Exception {
-    modEntries(ldif, bindDn, bindPassword, true, false);
+    modEntries(ldif, bindDn, bindPassword, null, true, false);
   }
 
-  /**
-   *
-   */
-  private void modEntriesExpectFailure(String ldif, String bindDn, String bindPassword) throws Exception {
-    modEntries(ldif, bindDn, bindPassword, false, false);
+  private void
+  modEntries(String ldif, String bindDn, String bindPassword, String proxyDN)
+          throws Exception {
+    modEntries(ldif, bindDn, bindPassword, proxyDN, true, false);
+  }
+
+  private void modEntriesExpectFailure(String ldif, String bindDn,
+                                       String bindPassword) throws Exception {
+    modEntries(ldif, bindDn, bindPassword, null, false, false);
   }
 
   private void _modEntries(String ldif, String bindDn, String bindPassword,
@@ -2031,7 +2176,8 @@
   }
 
     private void modEntries(String ldif, String bindDn, String bindPassword,
-                          boolean expectSuccess, boolean contFlag)
+                          String proxyDN, boolean expectSuccess,
+                          boolean contFlag)
     throws Exception {
     File tempFile = getTemporaryLdifFile();
     TestCaseUtils.writeFile(tempFile, ldif);
@@ -2048,6 +2194,10 @@
     argList.add(tempFile.getAbsolutePath());
     if(contFlag)
         argList.add("-c");
+    if(proxyDN != null) {
+        argList.add("-Y");
+        argList.add("dn:" + proxyDN);
+    }
     String[] args = new String[argList.size()];
     ldapModify(argList.toArray(args), expectSuccess);
   }
@@ -2065,7 +2215,7 @@
                 "changetype: modify",
                 "delete: " + attr,
                 attr + ":" + val));
-        modEntries(ldif.toString(), bindDN, pwd, errorOk, false);
+        modEntries(ldif.toString(), bindDN, pwd, null, errorOk, false);
     }
 
 
@@ -2090,7 +2240,7 @@
                   "dn: "  + dn,
                   "changetype: modify",
                   "delete: " + attr));
-          modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, errorOk, false);
+          modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW,  null, errorOk, false);
       }
 
     private void deleteEntries(String[] entries) throws Exception {
@@ -2102,7 +2252,7 @@
                     "changetype: delete"
             ));
         }
-        modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, true, true);
+        modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, null, true, true);
     }
 
   /**
@@ -2214,7 +2364,8 @@
             "cn: " +  cn,
             "sn: " + sn,
             "givenName: " + givenName,
-            "userpassword: " + password);
+            "userpassword: " + password,
+            "ds-privilege-name: proxied-auth");
   }
 
     private static String makeUserLdif(String dn, String givenName, String sn,

--
Gitblit v1.10.0