mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

dugan
19.28.2007 a8a8f5354938c4b5b84debd445a5d8dc0b037bd9
Add support for:

1. global ACI implementation using the ds-cfg-global-aci attribute type
2. re-adds support for ACIs in the "cn=config" naming context

9 files modified
539 ■■■■ changed files
opendj-sdk/opends/resource/config/config.ldif 1 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/resource/schema/02-config.ldif 9 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java 176 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java 183 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java 55 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java 63 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java 5 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java 40 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java 7 ●●●●● patch | view | raw | blame | history
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
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 )
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;
                       }
                   }
               }
            }
        }
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;
  }
  /**
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())
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.");
    }
}
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;
    }
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))
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