From a8a8f5354938c4b5b84debd445a5d8dc0b037bd9 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Mon, 19 Mar 2007 22:28:03 +0000
Subject: [PATCH] Add support for:

---
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java         |   40 +++-
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java            |  183 +++++++++++++-------
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java |   55 +++---
 opendj-sdk/opends/resource/config/config.ldif                                                   |    1 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java         |  176 +++++++++++++++++--
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java        |    5 
 opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java                      |    7 
 opendj-sdk/opends/resource/schema/02-config.ldif                                                |    9 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java        |   63 +++++++
 9 files changed, 407 insertions(+), 132 deletions(-)

diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index f4ea507..1eedfcf 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -50,6 +50,7 @@
 dn: cn=Access Control Handler,cn=config
 objectClass: top
 objectClass: ds-cfg-access-control-handler
+objectClass: ds-cfg-dseecompat-access-control-handler
 cn: Access Control Handler
 ds-cfg-acl-handler-class: org.opends.server.authorization.dseecompat.AciProvider
 ds-cfg-acl-handler-enabled: false
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index 4d0a77e..4689f35 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -150,6 +150,8 @@
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.39
   NAME 'ds-cfg-fixed-time-limit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.320  NAME 'ds-cfg-global-aci'
+  SYNTAX 1.3.6.1.4.1.26027.1.3.4 X-ORIGIN 'OpenDS Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.40
   NAME 'ds-cfg-index-attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
@@ -1084,11 +1086,16 @@
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.319
   NAME 'ds-cfg-changelog-purge-delay'
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE
-  X-ORIGIN 'OpenDS Directory Server' ) 
+  X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
   MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
   X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.87
+  NAME 'ds-cfg-dseecompat-access-control-handler'
+  SUP ds-cfg-access-control-handler
+  STRUCTURAL MAY ds-cfg-global-aci
+  X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.2
   NAME 'ds-cfg-alert-handler' SUP top STRUCTURAL
   MUST ( cn $ ds-cfg-alert-handler-class $ ds-cfg-alert-handler-enabled )
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 2522545..b5729db 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
@@ -35,9 +35,17 @@
 import static org.opends.server.messages.MessageHandler.getMessage;
 import org.opends.server.types.*;
 import static org.opends.server.util.StaticUtils.toLowerCase;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import org.opends.server.config.StringConfigAttribute;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.debugCaught;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+
+import java.util.*;
 
 /**
  * The AciHandler class performs the main processing for the
@@ -57,21 +65,138 @@
     public static AttributeType aciType;
 
     /**
-     * Constructor that creates the ACI list
-     * class that manages the ACI list. Instantiates and registers the change
-     * notification listener that is used to manage the ACI list on
-     * modifications and the backend initialization listener that is used to
-     * register/de-register aci attribute types in backends when backends
-     * are initialized/finalized.
+     * Attribute type corresponding to global "ds-cfg-global-aci" attribute.
+     */
+    public static AttributeType globalAciType;
+
+    /**
+     * This constructor instantiates the ACI handler class that performs the
+     * main processing for the dseecompat ACI package. It does the following
+     * initializations:
+     *
+     *  - Instantiates the ACI list cache.
+     *
+     *  - Instantiates and registers the change notification listener that is
+     *    used to manage the ACI list cache after ACI modifications have been
+     *    performed.
+     *
+     *  - Instantiates and registers the backend initialization listener that is
+     *    used to manage the ACI list cache when backends are
+     *    initialized/finalized.
+     *
+     *  - Processes all global attribute types found in the configuration entry
+     *    and adds them to the ACI list cache.
+     *
+     *  - Processes all "aci" attributes found in the "cn=config" naming
+     *    context and adds them to the ACI list cache.
+     *
+     * @param configEntry The configuration entry passed in from the provider.
+     * @throws InitializationException if there is a problem processing the
+     * config entry or config naming context.
     */
-    public AciHandler() {
-        aciList = new AciList();
+    public AciHandler(ConfigEntry configEntry) throws InitializationException  {
+        aciList = new AciList(configEntry.getDN());
         AciListenerManager aciListenerMgr =
             new AciListenerManager(aciList);
         DirectoryServer.registerChangeNotificationListener(aciListenerMgr);
         DirectoryServer.registerBackendInitializationListener(aciListenerMgr);
         if((aciType = DirectoryServer.getAttributeType("aci")) == null)
             aciType = DirectoryServer.getDefaultAttributeType("aci");
+        if((globalAciType =
+               DirectoryServer.getAttributeType(ATTR_AUTHZ_GLOBAL_ACI)) == null)
+            globalAciType =
+                 DirectoryServer.getDefaultAttributeType(ATTR_AUTHZ_GLOBAL_ACI);
+        processGlobalAcis(configEntry);
+        processConfigAcis();
+    }
+
+    /**
+     * Process all global ACI attribute types found in the configuration
+     * entry and adds them to that ACI list cache. It also logs messages about
+     * the number of ACI attribute types added to the cache. This method is
+     * called once at startup.
+     * @param configEntry  The configuraion entry to search for global ACIs.
+     * @throws InitializationException If there is an error reading
+     * the global ACIs from the configuration entry.
+     */
+    private void processGlobalAcis(ConfigEntry configEntry)
+    throws InitializationException {
+        int msgID = MSGID_ACI_DESCRIPTION_GLOBAL_ACI;
+        StringConfigAttribute aciGlobalStub =
+                new StringConfigAttribute(ATTR_AUTHZ_GLOBAL_ACI,
+                        getMessage(msgID), false, true, false);
+        try {
+            StringConfigAttribute aciGlobalAttr =
+                    (StringConfigAttribute)
+                            configEntry.getConfigAttribute(aciGlobalStub);
+            if (aciGlobalAttr != null)   {
+                Attribute attr = new Attribute(globalAciType,
+                        globalAciType.toString(),
+                        aciGlobalAttr.getActiveValues());
+                Entry e = new Entry(configEntry.getDN(), null, null, null);
+                e.addAttribute(attr, new ArrayList<AttributeValue>());
+                int aciCount =  aciList.addAci(e, false, true);
+                msgID  = MSGID_ACI_ADD_LIST_GLOBAL_ACIS;
+                String message = getMessage(msgID, Integer.toString(aciCount));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE,
+                        message, msgID);
+            }  else {
+                msgID  = MSGID_ACI_ADD_LIST_NO_GLOBAL_ACIS;
+                String message = getMessage(msgID);
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE, message, msgID);
+
+            }
+        }  catch (ConfigException e) {
+            if (debugEnabled())
+                debugCaught(DebugLogLevel.ERROR, e);
+            msgID = MSGID_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI;
+            String message =
+                    getMessage(msgID, String.valueOf(configEntry.getDN()),
+                    stackTraceToSingleLineString(e));
+            throw new InitializationException(msgID, message, e);
+        }
+    }
+
+    /**
+     * Process all ACIs under the "cn=config" naming context and adds them to
+     * the ACI list cache. It also logs messages about the number of ACIs added
+     * to the cache. This method is called once at startup.
+     * @throws InitializationException If there is an error searching for
+     * the ACIs in the naming context.
+     */
+    private void processConfigAcis() throws InitializationException {
+        try
+        {
+            DN configDN=DN.decode("cn=config");
+            LinkedHashSet<String> attrs = new LinkedHashSet<String>(1);
+            attrs.add("aci");
+            InternalClientConnection conn =
+                    InternalClientConnection.getRootConnection();
+            InternalSearchOperation op = conn.processSearch(configDN,
+                    SearchScope.WHOLE_SUBTREE,
+                    DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+                    SearchFilter.createFilterFromString("aci=*"), attrs);
+            if(op.getSearchEntries().isEmpty()) {
+                int    msgID  = MSGID_ACI_ADD_LIST_NO_ACIS;
+                String message = getMessage(msgID, String.valueOf(configDN));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE, message, msgID);
+            } else {
+                int validAcis = aciList.addAci(op.getSearchEntries());
+                int    msgID  = MSGID_ACI_ADD_LIST_ACIS;
+                String message = getMessage(msgID, Integer.toString(validAcis),
+                        String.valueOf(configDN));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE,
+                        message, msgID);
+            }
+        } catch (DirectoryException e) {
+            int  msgID = MSGID_ACI_HANDLER_FAIL_PROCESS_ACI;
+            String message = getMessage(msgID, stackTraceToSingleLineString(e));
+            throw new InitializationException(msgID, message, e);
+        }
     }
 
     /**
@@ -180,20 +305,25 @@
                    If so, check the syntax of that attribute value. Fail the
                    the operation if the syntax check fails.
                    */
-                  if(modType.equals(aciType)) {
-                      try {
-                          Aci.decode(v.getValue(),dn);
-                      } catch (AciException ex) {
-                          int    msgID  = MSGID_ACI_MODIFY_FAILED_DECODE;
-                          String message = getMessage(msgID,
-                                  String.valueOf(dn),
-                                  ex.getMessage());
-                          logError(ErrorLogCategory.ACCESS_CONTROL,
+                   if(modType.equals(aciType)  ||
+                      modType.equals(globalAciType)) {
+                       try {
+                           //A global ACI needs a NULL DN, not the DN of the
+                           //modification.
+                           if(modType.equals(globalAciType))
+                               dn=DN.nullDN();
+                           Aci.decode(v.getValue(),dn);
+                       } catch (AciException ex) {
+                           int    msgID  = MSGID_ACI_MODIFY_FAILED_DECODE;
+                           String message = getMessage(msgID,
+                                   String.valueOf(dn),
+                                   ex.getMessage());
+                           logError(ErrorLogCategory.ACCESS_CONTROL,
                                    ErrorLogSeverity.SEVERE_WARNING,
                                    message, msgID);
-                          return false;
-                      }
-                  }
+                           return false;
+                       }
+                   }
                }
             }
         }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
index d281e3f..bedad92 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -30,19 +30,11 @@
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
 import static org.opends.server.loggers.Error.logError;
 import static org.opends.server.messages.MessageHandler.getMessage;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.ArrayList;
 
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ErrorLogCategory;
-import org.opends.server.types.ErrorLogSeverity;
+import java.util.*;
+
+import static org.opends.server.authorization.dseecompat.AciHandler.*;
+import org.opends.server.types.*;
 import org.opends.server.api.Backend;
 
 /**
@@ -58,9 +50,23 @@
   private volatile LinkedHashMap<DN, List<Aci>> aciList =
        new LinkedHashMap<DN, List<Aci>>();
 
+  /*
+  * The configuration DN used to compare against the global ACI entry DN.
+  */
+  private DN configDN;
+
+  /**
+   * Constructor to create an ACI list to cache ACI attribute types.
+   * @param configDN The configuration entry DN.
+   */
+  public AciList(DN configDN) {
+     this.configDN=configDN;
+  }
+
   /**
    * Accessor to the ACI list intended to be called from within unsynchronized
    * read-only methods.
+   * @return   The current ACI list.
    */
   private LinkedHashMap<DN, List<Aci>> getList() {
     return aciList;
@@ -74,14 +80,13 @@
     return new LinkedHashMap<DN, List<Aci>>(aciList);
   }
 
-  /*
-  * TODO Add support for global ACIs in config.ldif.
-  *
-  */
   /**
    * Using the base DN, return a list of ACIs that are candidates for
    * evaluation by walking up from the base DN towards the root of the
-   * DIT gathering ACIs on parents.
+   * DIT gathering ACIs on parents. Global ACIs use the NULL DN as the key
+   * and are included in the candidate set only if they have no
+   * "target" keyword rules, or if the target keyword rule matches for
+   * the specified base DN.
    *
    * @param baseDN  The DN to check.
    * @return A list of candidate ACIs that might be applicable.
@@ -93,12 +98,26 @@
 
     // Save a reference to the current ACI list, in case it gets changed.
     LinkedHashMap<DN, List<Aci>> aciList = getList();
-
+    //Save the baseDN in case we need to evaluate a global ACI.
+    DN entryDN=baseDN;
     while(baseDN != null) {
       List<Aci> acis = aciList.get(baseDN);
-      if (acis != null)
-      {
-        candidates.addAll(acis);
+      if (acis != null) {
+       //Check if there are global ACIs. Global ACI has a NULL DN.
+       if(baseDN.isNullDN()) {
+           for(Aci aci : acis) {
+               AciTargets targets=aci.getTargets();
+               //If there is a target, evaluate it to see if this ACI should
+               //be included in the candidate set.
+               if(targets != null) {
+                   boolean ret=AciTargets.isTargetApplicable(aci, targets,
+                                                             entryDN);
+                   if(ret)
+                      candidates.add(aci);  //Add this ACI to the candidates.
+               }
+           }
+       } else
+           candidates.addAll(acis);
       }
       if(baseDN.isNullDN())
         break;
@@ -112,7 +131,9 @@
   }
 
   /**
-   * Add all the ACI from a set of entries to the ACI list.
+   * Add all the ACI from a set of entries to the ACI list. There is no need
+   * to check for global ACIs since they are processe by the AciHandler at
+   * startup using the addACi single entry method.
    * @param entries The set of entries containing the "aci" attribute values.
    * @return The number of valid ACI attribute values added to the ACI list.
    */
@@ -135,39 +156,47 @@
   }
 
   /**
-   * Add all of an entry's ACI attribute values to the ACI list.
-   * @param entry The entry containing the "aci" attribute values.
+   * Add all of an entry's ACI (global or regular) attribute values to the
+   * ACI list.
+   * @param entry The entry containing the ACI attributes.
+   * @param hasAci True if the "aci" attribute type was seen in the entry.
+   * @param hasGlobalAci True if the "ds-cfg-global-aci" attribute type was
+   * seen in the entry.
    * @return The number of valid ACI attribute values added to the ACI list.
    */
-  public synchronized int addAci(Entry entry) {
-    int validAcis;
-    DN dn=entry.getDN();
-    List<Attribute> attributeList =
-         entry.getOperationalAttribute(AciHandler.aciType);
-
-    if (attributeList == null) {
-      return 0;
-    }
+  public synchronized int addAci(Entry entry,  boolean hasAci,
+                                               boolean hasGlobalAci) {
+    int validAcis=0;
 
     // Copy the ACI list.
     LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
+    //Process global "ds-cfg-global-aci" attribute type. The oldentry
+    //DN is checked to verify it is equal to the config DN. If not those
+    //attributes are skipped.
+    if(hasGlobalAci && entry.getDN().equals(configDN)) {
+        List<Attribute> attributeList = entry.getAttribute(globalAciType);
+        validAcis = addAciAttributeList(aciCopy, DN.nullDN(), attributeList);
+    }
 
-    validAcis=addAciAttributeList(aciCopy, dn, attributeList);
-
+    if(hasAci) {
+        List<Attribute> attributeList = entry.getAttribute(aciType);
+        validAcis += addAciAttributeList(aciCopy, entry.getDN(), attributeList);
+    }
     // Replace the ACI list with the copy.
     aciList = aciCopy;
     return validAcis;
   }
 
   /**
-   * Add "aci" attribute type values to the ACI list. There is a chance
-   * that an ACI will throw an exception if it has an invalid syntax.
-   * If that happens a message will be logged and the ACI skipped.
+   * Add an ACI's attribute type values to the ACI list. There is a chance that
+   * an ACI will throw an exception if it has an invalid syntax. If that
+   * happens a message will be logged and the ACI skipped.  A count is
+   * returned of the number of valid ACIs added.
    * @param aciList The ACI list to which the ACI is to be added.
    * @param dn The DN to use as the key in the ACI list.
-   * @param attributeList List of attributes containing the "aci" attribute
+   * @param attributeList List of attributes containing the ACI attribute
    * values.
-   * @return The number of valid "aci" attribute values added to the ACI list.
+   * @return The number of valid attribute values added to the ACI list.
    */
   private static int addAciAttributeList(
        LinkedHashMap<DN,List<Aci>> aciList, DN dn,
@@ -209,26 +238,41 @@
   /**
    * Remove all of the ACIs related to the old entry and then add all of the
    * ACIs related to the new entry. This method locks/unlocks the list.
-   * @param oldEntry The old entry possibly containing old "aci" attribute
+   * In the case of global ACIs the DN of the entry is checked to make sure it
+   * is equal to the config DN. If not, the global ACI attribute type is
+   * silently skipped.
+   * @param oldEntry The old entry possibly containing old ACI attribute
    * values.
-   * @param newEntry The new entry possibly containing new "aci" attribute
+   * @param newEntry The new entry possibly containing new ACI attribute
    * values.
+   * @param hasAci True if the "aci" attribute type was seen in the entry.
+   * @param hasGlobalAci True if the "ds-cfg-global-aci" attribute type was
+   * seen in the entry.
    */
-  public synchronized void modAciOldNewEntry(Entry oldEntry, Entry newEntry) {
-    if((oldEntry.hasOperationalAttribute(AciHandler.aciType)) ||
-         (newEntry.hasOperationalAttribute(AciHandler.aciType))) {
+  public synchronized void modAciOldNewEntry(Entry oldEntry, Entry newEntry,
+                                             boolean hasAci,
+                                             boolean hasGlobalAci) {
 
       // Copy the ACI list.
       LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
-
-      aciCopy.remove(oldEntry.getDN());
-      List<Attribute> attributeList =
-           newEntry.getOperationalAttribute(AciHandler.aciType);
-      addAciAttributeList(aciCopy,newEntry.getDN(),attributeList);
-
+      //Process "aci" attribute types.
+      if(hasAci) {
+          aciCopy.remove(oldEntry.getDN());
+          List<Attribute> attributeList =
+                  newEntry.getOperationalAttribute(aciType);
+          addAciAttributeList(aciCopy,newEntry.getDN(),attributeList);
+      }
+      //Process global "ds-cfg-global-aci" attribute type. The oldentry
+      //DN is checked to verify it is equal to the config DN. If not those
+      //attributes are skipped.
+      if(hasGlobalAci && oldEntry.getDN().equals(configDN)) {
+          aciCopy.remove(DN.nullDN());
+          List<Attribute> attributeList =
+                  newEntry.getAttribute(globalAciType);
+          addAciAttributeList(aciCopy, DN.nullDN(), attributeList);
+      }
       // Replace the ACI list with the copy.
       aciList = aciCopy;
-    }
   }
 
   /**
@@ -251,21 +295,30 @@
   }
 
   /**
-   * Remove ACIs related to an entry.
-   * @param entry The entry to be removed.
-   * @return True if the ACI set was deleted.
+   * Remove global and regular ACIs from the list. It's possible that an entry
+   * could have both attribute types (aci and ds-cfg-global-aci). Global ACIs
+   * use the NULL DN for the key.  In the case of global ACIs the DN of the
+   * entry is checked to make sure it is equal to the config DN. If not, the
+   * global ACI attribute type is silently skipped.
+   * @param entry The entry containing the global ACIs.
+   * @param hasAci True if the "aci" attribute type was seen in the entry.
+   * @param hasGlobalAci True if the "ds-cfg-global-aci" attribute type was
+   * seen in the entry.
+   * @return  True if the ACI set was deleted.
    */
-  public synchronized boolean removeAci(Entry entry) {
-    // Copy the ACI list.
-    LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
+  public synchronized boolean removeAci(Entry entry,  boolean hasAci,
+                                                      boolean hasGlobalAci) {
+      // Copy the ACI list.
+      LinkedHashMap<DN,List<Aci>> aciCopy = copyList();
 
-    boolean deleted = false;
-    if (aciCopy.remove(entry.getDN()) != null)
-      deleted = true;
-
-    // Replace the ACI list with the copy.
-    aciList = aciCopy;
-    return deleted;
+      if(hasGlobalAci && entry.getDN().equals(configDN) &&
+         aciCopy.remove(DN.nullDN()) == null)
+          return false;
+      if(hasAci && aciCopy.remove(entry.getDN()) == null)
+          return false;
+      // Replace the ACI list with the copy.
+      aciList = aciCopy;
+      return true;
   }
 
   /**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index 3690dee..11b0a5e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -42,7 +42,6 @@
 import org.opends.server.types.*;
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
-
 import java.util.LinkedHashSet;
 import java.util.List;
 
@@ -97,10 +96,12 @@
      * @param entry The entry being deleted.
      */
     public void handleDeleteOperation(PostResponseDeleteOperation
-                                      deleteOperation, Entry entry) {
-       if(entry.hasOperationalAttribute(AciHandler.aciType)) {
-            aciList.removeAci(entry);
-       }
+            deleteOperation, Entry entry) {
+        boolean hasAci,  hasGlobalAci=false;
+        //This entry might have both global and aci attribute types.
+        if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) ||
+                (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType)))
+            aciList.removeAci(entry, hasAci, hasGlobalAci);
     }
 
     /**
@@ -111,10 +112,11 @@
      */
     public void handleAddOperation(PostResponseAddOperation addOperation,
                                    Entry entry) {
-        if(entry.hasOperationalAttribute(AciHandler.aciType))
-        {
-            aciList.addAci(entry);
-        }
+        boolean hasAci, hasGlobalAci=false;
+        //This entry might have both global and aci attribute types.
+        if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) ||
+                (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType)))
+            aciList.addAci(entry, hasAci, hasGlobalAci);
     }
 
     /**
@@ -128,23 +130,23 @@
     public void handleModifyOperation(PostResponseModifyOperation modOperation,
                                       Entry oldEntry, Entry newEntry)
     {
-      // A change to the ACI list is expensive so let's first make sure that
-      // the modification included changes to the ACI.
-      boolean hasAciMod = false;
-      List<Modification> mods = modOperation.getModifications();
-      for (Modification mod : mods)
-      {
-        if (mod.getAttribute().getAttributeType().equals(AciHandler.aciType))
-        {
-          hasAciMod = true;
-          break;
+        // A change to the ACI list is expensive so let's first make sure that
+        // the modification included changes to the ACI. We'll check for
+        //both "aci" attribute types and global "ds-cfg-global-aci" attribute
+        //types.
+        boolean hasAci = false, hasGlobalAci=false;
+        List<Modification> mods = modOperation.getModifications();
+        for (Modification mod : mods) {
+            AttributeType attributeType=mod.getAttribute().getAttributeType();
+            if (attributeType.equals(AciHandler.aciType))
+                hasAci = true;
+           else if(attributeType.equals(AciHandler.globalAciType))
+                hasGlobalAci=true;
+            if(hasAci && hasGlobalAci)
+               break;
         }
-      }
-
-      if (hasAciMod)
-      {
-        aciList.modAciOldNewEntry(oldEntry, newEntry);
-      }
+        if (hasAci || hasGlobalAci)
+            aciList.modAciOldNewEntry(oldEntry, newEntry, hasAci, hasGlobalAci);
     }
 
     /**
@@ -191,8 +193,7 @@
                   null, baseDN, SearchScope.WHOLE_SUBTREE,
                   DereferencePolicy.NEVER_DEREF_ALIASES,
                   0, 0, false, aciFilter, attrs, null);
-        try
-        {
+        try  {
           backend.search(internalSearch);
         } catch (Exception e) {
           if (debugEnabled())
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
index 76856ca..b026612 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
 
 /**
  * The AciMessages class defines the set of message IDs and default format
@@ -653,6 +654,48 @@
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 63;
 
     /**
+     * The message ID for the message that will be used as the description of
+     * the configuration attribute specifying a global ACI.
+     */
+    public static final
+    int MSGID_ACI_DESCRIPTION_GLOBAL_ACI = CATEGORY_MASK_ACCESS_CONTROL | 64;
+
+
+    /**
+     * The message ID for the ACI message that will be generated the server
+     * searches an directory context for Global "aci" attribute types and
+     * finds none. This takes no arguments.
+     */
+    public static final int MSGID_ACI_ADD_LIST_NO_GLOBAL_ACIS =
+        CATEGORY_MASK_ACCESS_CONTROL | 65;
+
+    /**
+     * The message ID for the ACI message that will be generated the server
+     * searches the config entry for Global "aci" attribute types and
+     * finds some. This takes one argument, which is the number of
+     * valid Global ACIs decoded.
+     */
+    public static final int MSGID_ACI_ADD_LIST_GLOBAL_ACIS =
+        CATEGORY_MASK_ACCESS_CONTROL | 66;
+
+    /**
+     * The message ID for the ACI message that will be generated when the server
+     * searches the config entry for Global "aci" attribute types and
+     * an error occurs. This takes one argument, which is the DN of the
+     * access control configuration entry.
+     */
+    public static final int MSGID_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI =
+        CATEGORY_MASK_ACCESS_CONTROL | 67;
+
+    /**
+     * The message ID for the ACI message that will be generated when the server
+     * searches the config system for "aci" attribute types and
+     * an error occurs. This takes no arguments.
+     */
+    public static final int MSGID_ACI_HANDLER_FAIL_PROCESS_ACI =
+        CATEGORY_MASK_ACCESS_CONTROL | 68;
+
+    /**
      * Associates a set of generic messages with the message IDs defined in
      * this class.
      */
@@ -1033,6 +1076,26 @@
              "with an ASCII letter and must contain only ASCII letters," +
               "digits or the \"-\" character.");
 
+        registerMessage(MSGID_ACI_DESCRIPTION_GLOBAL_ACI,
+             "Specifies a global Access Control Instruction (ACI) "  +
+             "attribute type that can be used to defined ACIs that have " +
+             "global scope accross naming contexts.");
+
+        registerMessage(MSGID_ACI_ADD_LIST_NO_GLOBAL_ACIS,
+            "No Global Access Control Instruction (ACI) attribute types were" +
+           " found.");
+
+        registerMessage(MSGID_ACI_ADD_LIST_GLOBAL_ACIS,
+                "Added %s Global Access Control Instruction (ACI) attribute " +
+                "types to the access control evaluation engine.");
+
+        registerMessage(MSGID_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI,
+         "An unexpected error occurred while processing the " +
+         ATTR_AUTHZ_GLOBAL_ACI + " attribute in configuration entry %s.");
+
+        registerMessage(MSGID_ACI_HANDLER_FAIL_PROCESS_ACI,
+         "An unexpected error occurred while processing the " +
+          " aci attributes in the configuration system.");
 
     }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
index be0478b..cfa8f05 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
@@ -60,7 +60,7 @@
      */
     public void initializeAccessControlHandler(ConfigEntry configEntry)
     throws ConfigException, InitializationException {
-        getInstance();
+         instance=new AciHandler(configEntry);
     }
 
     /**
@@ -68,9 +68,6 @@
      * @return  A new AciHandler instance.
      */
     public  AccessControlHandler getInstance() {
-        if (instance == null) {
-            instance = new AciHandler();
-        }
         return instance;
     }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
index 3875ca4..e9e5c27 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -440,6 +440,21 @@
          return  ((skipRights & rights) == rights);
     }
 
+
+    /**
+     * Wrapper class that passes an ACI, an ACI's targets and the specified
+     * target match context's resource entry DN to the main isTargetApplicable
+     * method.
+     * @param aci The ACI currently be matched.
+     * @param matchCtx The target match context to match against.
+     * @return True if the target matched the ACI.
+     */
+    public static boolean isTargetApplicable(Aci aci,
+                                             AciTargetMatchContext matchCtx) {
+        return isTargetApplicable(aci, aci.getTargets(),
+                                        matchCtx.getResourceEntry().getDN());
+    }
+
     /*
      * TODO Investigate supporting alternative representations of the scope.
      *
@@ -449,24 +464,24 @@
      * abbreviations in widespread use for those terms?
      */
     /**
-     * Checks an provided ACI's target information against an target match
-     * context.
+     * Main target isApplicable method. This method performs the target keyword
+     * match functionality, which allows for directory entry "targeting" using
+     * the specifed ACI, ACI targets class and DN.
      * @param aci The ACI to match the target against.
-     * @param matchCtx The target match context to check the ACI against.
-     * @return True if the target matched the context.
+     * @param targets The targets to use in this evaluation.
+     * @param entryDN The DN to use in this evaluation.
+     * @return True if the ACI matched the target and DN.
      */
-    public static boolean isTargetApplicable(Aci aci,
-            AciTargetMatchContext matchCtx) {
-        boolean ret=true;
-        DN entryDN=matchCtx.getResourceEntry().getDN();
-        DN targetDN=aci.getDN();
-        AciTargets targets=aci.getTargets();
 
+    public static boolean isTargetApplicable(Aci aci,
+            AciTargets targets, DN entryDN) {
+        boolean ret=true;
+        DN targetDN=aci.getDN();
         /*
          * Scoping of the ACI uses either the DN of the entry
          * containing the ACI (aci.getDN above), or if the ACI item
-         * contains a simple target DN and a equality operator that
-         * target DN is used.
+         * contains a simple target DN and a equality operator, that
+         * simple target DN is used as the target DN.
          */
         if((targets.getTarget() != null) &&
                 (!targets.getTarget().isPattern())) {
@@ -474,6 +489,7 @@
             if(op != EnumTargetOperator.NOT_EQUALITY)
                 targetDN=targets.getTarget().getDN();
         }
+        //Check if the scope is correct.
         switch(targets.getTargetScope()) {
         case BASE_OBJECT:
             if(!targetDN.equals(entryDN))
diff --git a/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java b/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
index 096ea89..28c167c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -2269,6 +2269,13 @@
        NAME_PREFIX_CFG + "acl-handler-enabled";
 
 
+    /**
+     * The name of the configuration attribute that specifies a global
+     * attribute access control instruction.
+     */
+    public static final String ATTR_AUTHZ_GLOBAL_ACI =
+        NAME_PREFIX_CFG + "global-aci";
+
 
   /**
    * The name of the configuration attribute that specifies the fully-qualified

--
Gitblit v1.10.0