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

dugan
21.56.2007 d428f48a4cf79de5e3f7cbc38a2c1af7a0b80e4f
opends/resource/config/config.ldif
@@ -51,6 +51,8 @@
objectClass: top
objectClass: ds-cfg-access-control-handler
objectClass: ds-cfg-dseecompat-access-control-handler
ds-cfg-global-aci: (targetcontrol="2.16.840.1.113730.3.4.2 || 2.16.840.1.113730.3.4.17 || 2.16.840.1.113730.3.4.19 || 1.3.6.1.4.1.4203.1.10.2") (version 3.0; acl "Anonymous control access"; allow(read) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetcontrol="*") (version 3.0; acl "control"; allow(read) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetattr!="userPassword||authPassword")(version 3.0; acl "Anonymous read access"; allow (read,search,compare) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetattr="*")(version 3.0; acl "Self entry modification"; allow (write) userdn="ldap:///self";)
ds-cfg-global-aci: (target="ldap:///cn=schema")(targetscope="base")(targetattr="attributeTypes||dITContentRules||dITStructureRules||ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||objectClasses")(version 3.0; acl "User-Visible Schema Operational Attributes"; allow (read,search,compare) userdn="ldap:///anyone";)
@@ -95,19 +97,7 @@
objectClass: ds-cfg-alert-handler
cn: JMX Alert Handler
ds-cfg-alert-handler-class: org.opends.server.extensions.JMXAlertHandler
ds-cfg-alert-handler-enabled: true
dn: cn=SMTP Alert Handler,cn=Alert Handlers,cn=config
objectClass: top
objectClass: ds-cfg-alert-handler
objectClass: ds-cfg-smtp-alert-handler
cn: JMX Alert Handler
ds-cfg-alert-handler-class: org.opends.server.extensions.SMTPAlertHandler
ds-cfg-alert-handler-enabled: false
ds-cfg-sender-address: opends-alerts@example.com
ds-cfg-recipient-address: directory-administrators@example.com
ds-cfg-message-subject: OpenDS Alert %%alert-type%%
ds-cfg-message-body: Alert Type:  %%alert-type%%\n\nAlert ID:  %%alert-id%%\n\nAlert Message:  %%alert-message%%
dn: cn=Backends,cn=config
objectClass: top
opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -133,6 +133,26 @@
                                         addOperation);
  /**
   * Indicates whether the provided control is allowed based on
   * the access control configuration and the specified
   * operation. This method should not alter the provided
   * operation in any way.
   *
   * @param  dn  A DN that can be used in the access determination.
   *
   * @param  op  The operation to use in the
   *                       determination.
   *
   * @param control The control for which to make the determination.
   *
   * @return  {@code true} if the control should be allowed by the
   *          access control configuration, or {@code false} if not.
   */
  public abstract boolean isAllowed(DN dn, Operation  op,
                                    Control control);
  /**
   * Indicates whether the provided bind operation is allowed based on
@@ -302,44 +322,5 @@
  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} if the operation should be allowed to use
   *          the proxied authorization control, or {@code false} if
   *          not.
   */
  public abstract boolean isProxiedAuthAllowed(Operation operation,
                               Entry newAuthorizationEntry);
  /**
   * Indicates whether a getEffectiveRights control is allowed
   * based on the current operation and the control contents.
   *
   * @param  operation  The operation with which the
   *                    getEffectiveRights control is associated.
   *                    This is always a SearchOperation.
   * @param  control    The control class containing the decoded
   *                    getEffectiveRights control contents.
   *
   * @return  {@code true} if the use of the getEffectiveRights
   *          control should be allowed, or {@code false} if not.
   */
  public abstract boolean isGetEffectiveRightsAllowed(
                               SearchOperation operation,
                               Control control);
}
opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -31,7 +31,10 @@
import org.opends.server.types.DN;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.AciMessages.*;
import static org.opends.server.util.StaticUtils.isDigit;
import java.util.regex.Pattern;
import java.util.HashSet;
/**
 * The Aci class represents ACI strings.
@@ -107,6 +110,7 @@
           ZERO_OR_MORE_WHITESPACE + AciBody.bodyRegx +
           ZERO_OR_MORE_WHITESPACE_END_PATTERN;
    /**
     * Regular expression that graciously matches an attribute type name. Must
     * begin with an ASCII letter or digit, and contain only ASCII letters,
@@ -162,6 +166,20 @@
            ZERO_OR_MORE_WHITESPACE +
                    "\\+" + ZERO_OR_MORE_WHITESPACE;
    /*
     * Regular expression used to do quick check of OID string.
     */
    private static final String OID_NAME = "[\\d.\\*]*";
    /*
    * Regular expression that matches one or more OID_NAME's separated by
    * the "||" token.
    */
    private static final String oidListRegex  =  ZERO_OR_MORE_WHITESPACE +
            OID_NAME + ZERO_OR_MORE_WHITESPACE + "(" +
            LOGICAL_OR + ZERO_OR_MORE_WHITESPACE + OID_NAME +
            ZERO_OR_MORE_WHITESPACE + ")*";
    /**
     * ACI_ADD is used to set the container rights for a LDAP add operation.
     */
@@ -409,6 +427,7 @@
              return false;
        }
        return AciTargets.isTargetApplicable(aci, matchCtx) &&
                AciTargets.isTargetControlApplicable(aci, matchCtx) &&
                AciTargets.isTargetFilterApplicable(aci, matchCtx) &&
                AciTargets.isTargAttrFiltersApplicable(aci, matchCtx) &&
                AciTargets.isTargetAttrApplicable(aci, matchCtx);
@@ -455,11 +474,79 @@
        return aci.evaluate(evalCtx);
    }
  /**
   * Returns the name string of this ACI.
   * @return The name string.
   */
    /**
     * Returns the name string of this ACI.
     * @return The name string.
     */
    public String getName() {
      return this.body.getName();
    }
}
  /**
   *  Decode an OIDs expression string.
   *
   * @param expr A string representing the OID expression.
   * @param msgID A message ID to be used if there is an exception.
   *
   * @return  Return a hash set of verfied OID strings parsed from the OID
   *          expression.
   *
   * @throws AciException If the specified expression string is invalid.
   */
    public static HashSet<String> decodeOID(String expr, int msgID)
    throws AciException {
      HashSet<String> OIDs = new HashSet<String>();
      //Quick check to see if the expression is valid.
      if (Pattern.matches(oidListRegex, expr)) {
        // Remove the spaces in the oid string and
        // split the list.
        Pattern separatorPattern =
                Pattern.compile(LOGICAL_OR);
        String oidString =
                expr.replaceAll(ZERO_OR_MORE_WHITESPACE, "");
        String[] oidArray=
                separatorPattern.split(oidString);
        //More careful analysis of each OID string.
        for(String oid : oidArray) {
          verifyOid(oid);
          OIDs.add(oid);
        }
      } else {
        String message = getMessage(msgID, expr);
        throw new AciException(msgID, message);
      }
      return OIDs;
    }
    /**
     *  Verfiy the specified OID string.
     *
     * @param oidStr The string representing an OID.
     *
     * @throws AciException If the specified string is invalid.
     */
    private static void verifyOid(String oidStr) throws AciException {
      int pos=0, length=oidStr.length();
      char c;
      if(oidStr.equals("*"))
        return;
      boolean lastWasPeriod = false;
      while ((pos < length) && ((c = oidStr.charAt(pos++)) != ' ')) {
        if (c == '.') {
          if (lastWasPeriod) {
            int msgID = MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID;
            String message = getMessage(msgID, oidStr, c, pos-1);
            throw new AciException(msgID, message);
          }  else
            lastWasPeriod = true;
        }  else if (! isDigit(c)) {
          int msgID = MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID;
          String message = getMessage(msgID, oidStr, c, pos-1);
          throw new AciException(msgID, message);
        }  else
          lastWasPeriod = false;
      }
    }
  }
opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -107,17 +107,17 @@
     * restore the current resource entry state after a read right was
     * evaluated.
     */
    private Entry saveResourceEntry;
    private final Entry saveResourceEntry;
    /*
     * The client connection information.
     */
    private ClientConnection clientConnection;
    private final ClientConnection clientConnection;
    /*
     * The operation being evaluated.
     */
    private Operation operation;
    private final Operation operation;
    /*
     * True if a targattrfilters match was found.
@@ -138,7 +138,7 @@
     * Used to save the current authorization entry when the authorization
     * entry is switched during a proxy access check.
     */
    private Entry saveAuthorizationEntry;
    private final Entry saveAuthorizationEntry;
    /*
     * This entry is only used if proxied authorization is being used.  It is
@@ -196,7 +196,7 @@
     * Table of ACIs that have targattrfilter keywords that matched. Used
     * in geteffectiverights attributeLevel write evaluation.
     */
    private HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
    private final HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
    /*
     * The name of a ACI that decided an evaluation and contained a
@@ -236,6 +236,11 @@
    */
    private int evalAllAttributes=0;
   /*
   * String used to hold a control OID string.
   */
    private String controlOID;
  /**
     * This constructor is used by all currently supported LDAP operations.
     *
@@ -732,6 +737,22 @@
    }
    /**
    * {@inheritDoc}
    */
    public String getControlOID() {
      return controlOID;
    }
    /**
     * Set the the controlOID value to the specified oid string.
     *
     * @param oid  The control oid string.
     */
    protected void setControlOID(String oid) {
      this.controlOID=oid;
    }
    /**
     * {@inheritDoc}
     */
    public EnumEvalResult hasAuthenticationMethod(EnumAuthMethod authMethod,
opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -37,7 +37,7 @@
import static org.opends.server.messages.AciMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import static org.opends.server.schema.SchemaConstants.SYNTAX_DN_OID;
import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import static org.opends.server.util.StaticUtils.toLowerCase;
@@ -53,7 +53,7 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.types.*;
import org.opends.server.workflowelement.localbackend.*;
import org.opends.server.controls.GetEffectiveRights;
/**
@@ -1153,32 +1153,37 @@
      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;
  }
  /**
   * Called when a geteffectiverights request control was decoded. Currently
   * used to save the control in the specified operation's attachment list.
   * Eventually will be used to check access to the actual control.
   * @param operation The operation to save the attachment to.
   * @param c  The request control to save.
   * @return  True if the control is allowed access.
   * {@inheritDoc}
   */
  public boolean isGetEffectiveRightsAllowed(SearchOperation operation,
                                             Control c) {
    operation.setAttachment(OID_GET_EFFECTIVE_RIGHTS, c);
    return true;
  @Override
  public boolean isAllowed(DN entryDN, Operation op, Control control) {
    boolean ret;
    if(!(ret=skipAccessCheck(op))) {
      Entry e = new Entry(entryDN, null, null, null);
      AciLDAPOperationContainer operationContainer =
              new AciLDAPOperationContainer(op, e, control.getOID());
      ret=accessAllowed(operationContainer);
    }
    if(control.getOID().equals(OID_PROXIED_AUTH_V2) ||
            control.getOID().equals(OID_PROXIED_AUTH_V1))
      op.setAttachment(ORIG_AUTH_ENTRY, op.getAuthorizationEntry());
    else if(control.getOID().equals(OID_GET_EFFECTIVE_RIGHTS)) {
      try {
        GetEffectiveRights getEffectiveRightsControl =
                GetEffectiveRights.decodeControl(control);
        op.setAttachment(OID_GET_EFFECTIVE_RIGHTS, getEffectiveRightsControl);
      } catch  (LDAPException le)  {
        int msgID=MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL;
        String message = getMessage(msgID, le.getMessage());
        logError(ErrorLogCategory.ACCESS_CONTROL,
                 ErrorLogSeverity.INFORMATIONAL,
                 message, msgID);
        ret=false;
      }
    }
    return ret;
  }
  //Not planned to be implemented methods.
opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -30,10 +30,9 @@
import java.util.List;
import org.opends.server.core.*;
import org.opends.server.types.Modification;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.Entry;
import org.opends.server.types.*;
import org.opends.server.workflowelement.localbackend.*;
import static org.opends.server.authorization.dseecompat.Aci.ACI_READ;
/**
 * The AciLDAPOperationContainer is an AciContainer
@@ -65,6 +64,18 @@
    }
    /**
     * Constructor interface for control evaluation.
     *
     * @param operation The operation to evaluate.
     * @param e An entry built especially for control evaluation.
     * @param oid The control's oid string.
     */
    public AciLDAPOperationContainer(Operation operation, Entry e, String oid) {
      super(operation, (ACI_READ), e );
      setControlOID(oid);
    }
    /**
     * Constructor interface for the add operation.
     * @param operation The add operation to evaluate.
     * @param rights  The rights of an add operation.
@@ -81,8 +92,7 @@
     * @param rights  The rights of a delete operation.
     */
    public AciLDAPOperationContainer(LocalBackendDeleteOperation operation,
        int rights)
    {
                                     int rights) {
        super(operation, rights, operation.getEntryToDelete());
    }
opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -118,6 +118,13 @@
     */
    public int getRights();
  /**
   * Return the oid string of the control being evaluated.
   *
   * @return The oid string of the control being evaluated.
   */
    public String getControlOID();
    /**
     * Checks if the container's rights has the specified rights.
     * @param  rights The rights to check for.
opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -71,6 +71,11 @@
     */
    private TargAttrFilters targAttrFilters=null;
   /**
    * The ACI syntax has a targetcontrol keyword.
    */
    private TargetControl targetControl=null;
    /*
     * The number of regular expression group positions in a valid ACI target
     * expression.
@@ -139,16 +144,19 @@
     * @param targetFilter The ACI targetfilter keyword if any.
     * @param targetScope The ACI targetscope keyword if any.
     * @param targAttrFilters The ACI targAttrFilters keyword if any.
     * @param targetControl The ACI targetControl keyword if any.
     */
    private AciTargets(Target targetEntry, TargetAttr targetAttr,
                       TargetFilter targetFilter,
                       SearchScope targetScope,
                       TargAttrFilters targAttrFilters) {
                       TargAttrFilters targAttrFilters,
                       TargetControl targetControl) {
       this.target=targetEntry;
       this.targetAttr=targetAttr;
       this.targetScope=targetScope;
       this.targetFilter=targetFilter;
       this.targAttrFilters=targAttrFilters;
       this.targetControl=targetControl;
    }
    /**
@@ -194,6 +202,16 @@
    public TargAttrFilters getTargAttrFilters() {
        return targAttrFilters;
    }
   /**
    * Return the class representing the ACI targetcontrol keyword. May be
    * null.
    * @return The targetcontrol information.
   */
    public TargetControl getTargetControl() {
      return targetControl;
    }
    /**
     * Decode an ACI's target part of the syntax from the string provided.
     * @param input String representing an ACI target part of syntax.
@@ -207,6 +225,7 @@
        TargetAttr targetAttr=null;
        TargetFilter targetFilter=null;
        TargAttrFilters targAttrFilters=null;
        TargetControl targetControl=null;
        SearchScope targetScope=SearchScope.WHOLE_SUBTREE;
        Pattern targetPattern = Pattern.compile(targetRegex);
        Matcher targetMatcher = targetPattern.matcher(input);
@@ -252,6 +271,22 @@
                }
                break;
            }
            case KEYWORD_TARGETCONTROL:
            {
                if (targetControl == null){
                    targetControl =
                            TargetControl.decode(targetOperator, expression);
                }
                else
                {
                    int msgID =
                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
                    String message =
                        getMessage(msgID, "targetcontrol", input);
                    throw new AciException(msgID, message);
                }
                break;
            }
            case KEYWORD_TARGETATTR:
            {
                if (targetAttr == null){
@@ -318,7 +353,7 @@
            }
        }
        return new AciTargets(target, targetAttr, targetFilter,
                              targetScope, targAttrFilters);
                              targetScope, targAttrFilters, targetControl);
    }
    /**
@@ -365,6 +400,23 @@
    }
    /**
     * Check an ACI's targetcontrol against a target match context.
     *
     * @param aci The ACI to match the targetcontrol against.
     * @param matchCtx The target match context containing the information
     *                 needed to perform the target match.
     * @return  True if the targetcontrol matched the target context.
     */
    public static boolean isTargetControlApplicable(Aci aci,
                                            AciTargetMatchContext matchCtx) {
      boolean ret=true;
      TargetControl targetControl=aci.getTargets().getTargetControl();
      if(targetControl != null)
        ret=targetControl.isApplicable(matchCtx);
      return ret;
    }
    /**
     * Check an ACI's targattrfilters against a target match context.
     * @param aci The ACI to match the targattrfilters against.
     * @param matchCtx  The target match context containing the information
opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
@@ -56,7 +56,12 @@
     * This enumeration is returned when the target keyword is
     * "targattrfilters".
     */
    KEYWORD_TARGATTRFILTERS ("targattrfilters");
    KEYWORD_TARGATTRFILTERS ("targattrfilters"),
    /**
     * This enumeration is returned when the target keyword is
     * "targetcontrol".
     */
    KEYWORD_TARGETCONTROL ("targetcontrol");
    /*
     * The target keyword name.
opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
@@ -59,10 +59,10 @@
     */
    private HashSet<AttributeType> attributes = new HashSet<AttributeType>();
  /**
   * HashSet of the operational attribute types parsed by the constructor.
   */
  private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>();
    /**
     * HashSet of the operational attribute types parsed by the constructor.
     */
    private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>();
    /*
     * Regular expression that matches one or more ATTR_NAME's separated by
opends/src/server/org/opends/server/authorization/dseecompat/TargetControl.java
New file
@@ -0,0 +1,101 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.authorization.dseecompat;
import static org.opends.server.messages.AciMessages.*;
import java.util.HashSet;
/**
 * This class represents an ACI's targetcontrol keyword.
 */
public class TargetControl {
  /*
   * HashSet of OID strings parsed from the decode.
   */
  private HashSet<String> controlOIDS = new HashSet<String>();
 /*
  * Enumeration representing the targetcontrol operator.
  */
  private EnumTargetOperator op = EnumTargetOperator.EQUALITY;
  /**
   * Creates a class that can be used to evaluate a targetcontrol.
   *
   * @param op The operator of the targetfilter expression (=, !=).
   * @param controlOIDS  Set of control OIDS to use in the evaluation (may
   *                     contain wild-card '*').
   */
  private TargetControl(EnumTargetOperator op, HashSet<String> controlOIDS) {
    this.controlOIDS=controlOIDS;
    this.op=op;
  }
  /**
   *  Decode an targetcontrol expression string.
   *
   * @param operator  An enumeration representing the operator type.
   * @param expr A string representing the targetcontrol expression.
   * @return  A class representing the targetcontrol expression that can be
   *          used to evaluate an ACI.
   *
   * @throws AciException If the specified expression string is invalid.
   */
  public static TargetControl decode(EnumTargetOperator operator, String expr)
          throws AciException {
    HashSet<String> controlOIDs =
          Aci.decodeOID(expr,MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION);
    return new TargetControl(operator, controlOIDs);
  }
  /**
   * Check if a targetcontrol is applicable based on the provided target match
   * context.
   *
   * @param matchCtx The target match context to use in the check.
   * @return True if the targetcontrol is applicable based on the context.
   */
  public boolean isApplicable(AciTargetMatchContext matchCtx) {
    if(matchCtx.getControlOID() == null)
      return false;
    boolean ret = false;
    for(String oid : controlOIDS)
      if(oid.equals("*") || matchCtx.getControlOID().equals(oid)) {
        ret=true;
        break;
      }
   if(op.equals(EnumTargetOperator.NOT_EQUALITY))
          ret = !ret;
    return ret;
  }
}
opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -100,7 +100,6 @@
  }
  /**
   * {@inheritDoc}
   */
@@ -160,6 +159,17 @@
   * {@inheritDoc}
   */
  @Override
   public  boolean isAllowed(DN dn, Operation  op, Control control)
   {
     return true;
   }
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isAllowed(LocalBackendModifyDNOperation modifyDNOperation)
  {
    return true;
@@ -189,7 +199,6 @@
  }
  /**
   * {@inheritDoc}
   */
@@ -213,27 +222,5 @@
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isProxiedAuthAllowed(Operation operation, Entry entry)
  {
   return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isGetEffectiveRightsAllowed(SearchOperation operation,
                                             Control c)
  {
      return true;
  }
}
opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
@@ -60,6 +60,7 @@
import org.opends.server.types.DebugLogLevel;
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.*;
@@ -487,6 +488,15 @@
      {
        for (Control c : requestControls)
        {
          if (!AccessControlConfigManager.getInstance().
                  getAccessControlHandler().
                  isAllowed(this.getAuthorizationDN(), this, c)) {
            setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
            appendErrorMessage(getMessage(msgID, c.getOID()));
            skipPostOperation=true;
            break extendedProcessing;
          }
          if (! c.isCritical())
          {
            // The control isn't critical, so we don't care if it's supported
opends/src/server/org/opends/server/messages/AciMessages.java
@@ -913,7 +913,48 @@
     public static final int MSGID_ACI_SYNTAX_INVALID_NETMASK =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 90;
    /**
     * The message ID for the message that will be used if an "aci" attribute
     * type value parse failed because a targetcontrol keyword expression
     * did not parse.  This takes one argument, which is the targetcontrol
     * expression from the ACI.
     */
     public static final int MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 91;
    /**
     * The message ID for the message that will be used if an "aci" attribute
     * type value cannot be parsed because numeric OID contained an
     * illegal character.  This takes three arguments, which are the provided
     * value, the illegal character, and the position of that character.
     */
     public static final int
            MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID =
            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 92;
    /**
     * The message ID for the message that will be used if an "aci" attribute
     * type value cannot be parsed because the OID contained two
     * consecutive periods.  This takes two arguments, which are the provided
     * value and the position of the second period.
     */
    public static final int
            MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID =
            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 93;
     /**
     * The message ID for the message that will be used the ACI handler cannot
     * decode an geteffectiverights control. This takes one argument, the
     * message from the decode exception.
     */
    public static final int
            MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL =
            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 94;
  /**
     * Associates a set of generic messages with the message IDs defined in
     * this class.
     */
@@ -1435,5 +1476,30 @@
                 "IP address expression failed to parse because the " +
                 "netmask part of the expression \"%s\" has an invalid value");
      registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION,
              "The provided Access Control Instruction (ACI) " +
              "targetcontrol expression value \"%s\" is invalid. A valid " +
              "targetcontrol keyword expression value requires one or more " +
              "valid control OID strings in the following format: " +
              "oid [|| oid1] ... [|| oidn]");
        registerMessage(MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID,
                "The provided Access Control Instruction (ACI) " +
                "targetcontrol OID value \"%s\" could not be parsed " +
                 " because the value contained an illegal character %s " +
                 "at position %d");
        registerMessage(MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID,
                "The provided Access Control Instruction (ACI) " +
                "targetcontrol OID value \"%s\" could not be parsed " +
               " because the numeric OID " +
               "contained two consecutive periods at position %d");
        registerMessage(MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL,
                "The access control check failed because a" +
                " geteffectiverights control could not be" +
                " decoded because of the following reason: \"%s\"");
    }
}
opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6084,13 +6084,12 @@
  /**
   * The message ID for the message that will be used if a search
   * operation cannot be processed due to insufficient access rights caused
   * by an access control check on the geteffectiverights control. This message
   * takes a single argument, the name of the search operation's base entry.
   * The message ID for the message that will be used if a request control
   * cannot be used due to insufficient access rights. This message takes a
   * single argument, which is the OID string of the control being used.
   */
  public static final
  int MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS =
  int MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS =
    CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_ERROR | 611;
@@ -8348,8 +8347,9 @@
        "The entry %s cannot be modified due to insufficient access rights");
    registerMessage(MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS,
        "The entry %s cannot be searched due to insufficient access rights");
    registerMessage(MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS,
        "The entry %s cannot be searched due to insufficient access rights");
    registerMessage(MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS,
        "The request control with Object Identifier (OID) \"%s\" cannot be" +
        " used due to insufficient access rights");
    registerMessage(MSGID_BIND_OPERATION_INSECURE_SIMPLE_BIND,
                    "Rejecting a simple bind request for user %s because the " +
                    "password policy requires secure authentication");
opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -10484,7 +10484,7 @@
                    "ERROR:  No configuration changes were specified");
    registerMessage(MSGID_CONFIGDS_PORT_ALREADY_SPECIFIED,
                    "ERROR:  You have specified the value %s for different " +
                    "ports.");
                    "ports");
    registerMessage(MSGID_CONFIGDS_WROTE_UPDATED_CONFIG,
                    "Successfully wrote the updated Directory Server " +
                    "configuration");
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -56,7 +56,6 @@
import org.opends.server.api.plugin.PostOperationPluginResult;
import org.opends.server.api.plugin.PreOperationPluginResult;
import org.opends.server.controls.AuthorizationIdentityResponseControl;
import org.opends.server.controls.GetEffectiveRights;
import org.opends.server.controls.LDAPAssertionRequestControl;
import org.opends.server.controls.LDAPPostReadRequestControl;
import org.opends.server.controls.LDAPPostReadResponseControl;
@@ -214,7 +213,7 @@
  /**
   * Perform a local modify operation against the local backend.
   *
   * @param operation - The operation to perform
   * @param localOp - The operation to perform
   */
  private void processLocalModify(LocalBackendModifyOperation localOp)
  {
@@ -392,6 +391,17 @@
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (!AccessControlConfigManager.getInstance().
                     getAccessControlHandler().
                     isAllowed(entryDN, localOp, c))
            {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID, oid));
              skipPostOperation = true;
              break modifyProcessing;
            }
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
@@ -459,7 +469,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPreReadRequestControl)
              {
                preReadRequest = (LDAPPreReadRequestControl) c;
              }
@@ -486,7 +496,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPostReadRequestControl)
              {
                postReadRequest = (LDAPPostReadRequestControl) c;
              }
@@ -569,19 +579,6 @@
                break modifyProcessing;
              }
              if (AccessControlConfigManager.getInstance().
                      getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -650,18 +647,6 @@
                break modifyProcessing;
              }
              if (AccessControlConfigManager.getInstance().
                  getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -2545,6 +2530,17 @@
          Control c   = requestControls.get(i);
          String  oid = c.getOID();
          if (!AccessControlConfigManager.getInstance().
                  getAccessControlHandler().
                  isAllowed(baseDN, localOp, c))
          {
            localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
            localOp.appendErrorMessage(getMessage(msgID, oid));
            skipPostOperation = true;
            break searchProcessing;
          }
          if (oid.equals(OID_LDAP_ASSERTION))
          {
            LDAPAssertionRequestControl assertControl;
@@ -2696,18 +2692,6 @@
              break searchProcessing;
            }
            if (AccessControlConfigManager.getInstance().
                getAccessControlHandler().isProxiedAuthAllowed(localOp,
                    authorizationEntry) == false) {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID,
                  String.valueOf(baseDN)));
              skipPostOperation = true;
              break searchProcessing;
            }
            localOp.setAuthorizationEntry(authorizationEntry);
            if (authorizationEntry == null)
            {
@@ -2777,18 +2761,6 @@
              break searchProcessing;
            }
            if (AccessControlConfigManager.getInstance().
                getAccessControlHandler().isProxiedAuthAllowed(localOp,
                    authorizationEntry) == false) {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID,
                  String.valueOf(baseDN)));
              skipPostOperation = true;
              break searchProcessing;
            }
            localOp.setAuthorizationEntry(authorizationEntry);
            if (authorizationEntry == null)
            {
@@ -2884,48 +2856,6 @@
          {
            localOp.setVirtualAttributesOnly(true);
          }
          else if(oid.equals(OID_GET_EFFECTIVE_RIGHTS))
          {
            GetEffectiveRights effectiveRightsControl;
            if (c instanceof GetEffectiveRights)
            {
              effectiveRightsControl = (GetEffectiveRights) c;
            }
            else
            {
              try
              {
                effectiveRightsControl = GetEffectiveRights.decodeControl(c);
              }
              catch (LDAPException le)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, le);
                }
                localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
                localOp.appendErrorMessage(le.getMessage());
                break searchProcessing;
              }
            }
              if (!AccessControlConfigManager.getInstance()
                   .getAccessControlHandler().
                    isGetEffectiveRightsAllowed(localOp,
                        effectiveRightsControl)) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                 int msgID =
                        MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS;
                 localOp.appendErrorMessage(getMessage(msgID,
                     String.valueOf(baseDN)));
                 skipPostOperation = true;
                 break searchProcessing;
               }
          }
          // NYI -- Add support for additional controls.
          else if (c.isCritical())
          {
@@ -3151,7 +3081,7 @@
  /**
   * Perform a local bind operation against a local backend.
   *
   * @param operation - The operation to perform
   * @param localOp - The operation to perform
   */
  private void processLocalBind(LocalBackendBindOperation localOp)
  {
@@ -3241,6 +3171,16 @@
          Control c   = requestControls.get(i);
          String  oid = c.getOID();
          if (!AccessControlConfigManager.getInstance().
                  getAccessControlHandler(). isAllowed(bindDN, localOp, c))
          {
            localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
            localOp.appendErrorMessage(getMessage(msgID, oid));
            skipPostOperation = true;
            break bindProcessing;
          }
          if (oid.equals(OID_AUTHZID_REQUEST))
          {
            returnAuthzID = true;
@@ -4560,7 +4500,7 @@
  /**
   * Perform a local add operation against a local backend.
   *
   * @param operation - The operation to perform
   * @param localOp - The operation to perform
   */
  private void processLocalAdd(LocalBackendAddOperation localOp)
  {
@@ -5298,6 +5238,16 @@
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (!AccessControlConfigManager.getInstance().
                    getAccessControlHandler().isAllowed(parentDN, localOp, c))
            {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID, oid));
              skipPostOperation = true;
              break addProcessing;
            }
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
@@ -5365,7 +5315,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPostReadRequestControl)
              {
                postReadRequest = (LDAPPostReadRequestControl) c;
              }
@@ -5448,18 +5398,6 @@
                break addProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break addProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -5528,18 +5466,6 @@
                break addProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break addProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -5945,7 +5871,7 @@
  /**
   * Performs a local delete operation against a local backend.
   *
   * @param operation the operation to perform
   * @param localOp the operation to perform
   */
  private void processLocalDelete(LocalBackendDeleteOperation localOp)
  {
@@ -6095,6 +6021,16 @@
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (!AccessControlConfigManager.getInstance().
                     getAccessControlHandler().isAllowed(entryDN, localOp, c))
            {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID, oid));
              skipPostOperation = true;
              break deleteProcessing;
            }
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
@@ -6162,7 +6098,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPreReadRequestControl)
              {
                preReadRequest = (LDAPPreReadRequestControl) c;
              }
@@ -6245,18 +6181,6 @@
                break deleteProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break deleteProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -6325,18 +6249,6 @@
                break deleteProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                      authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break deleteProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -6755,7 +6667,7 @@
  /**
   * Perform a local compare operation against a local backend.
   *
   * @param operation - The operation to perform
   * @param localOp - The operation to perform
   */
  private void processLocalCompare(LocalBackendCompareOperation localOp)
  {
@@ -6896,6 +6808,17 @@
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (!AccessControlConfigManager.getInstance().
                    getAccessControlHandler().
                    isAllowed(entryDN, localOp, c))
            {
              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
              localOp.appendErrorMessage(getMessage(msgID, oid));
              skipPostOperation = true;
              break compareProcessing;
            }
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
@@ -7015,18 +6938,6 @@
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                                                 authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -7095,18 +7006,6 @@
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                                                 authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -7323,7 +7222,7 @@
  /**
   * Perform a local moddn operation against the local backend.
   *
   * @param operation - The operation to perform
   * @param op - The operation to perform
   */
  private void processLocalModifyDN(LocalBackendModifyDNOperation op)
  {
@@ -7606,6 +7505,16 @@
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (!AccessControlConfigManager.getInstance().
                     getAccessControlHandler().isAllowed(entryDN,  op, c))
            {
              op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
              op.appendErrorMessage(getMessage(msgID, oid));
              skipPostOperation = true;
              break modifyDNProcessing;
            }
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
@@ -7671,7 +7580,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPreReadRequestControl)
              {
                preReadRequest = (LDAPPreReadRequestControl) c;
              }
@@ -7698,7 +7607,7 @@
            }
            else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
            {
              if (c instanceof LDAPAssertionRequestControl)
              if (c instanceof LDAPPostReadRequestControl)
              {
                postReadRequest = (LDAPPostReadRequestControl) c;
              }
@@ -7780,18 +7689,6 @@
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(op,
                      authorizationEntry) == false) {
                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                op.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              op.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
@@ -7858,19 +7755,6 @@
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(op,
                                                authorizationEntry) == false) {
                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                op.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              op.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -31,6 +31,8 @@
import org.opends.server.TestCaseUtils;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.tools.LDAPDelete;
import org.opends.server.tools.LDAPPasswordModify;
import static org.opends.server.util.ServerConstants.EOL;
import org.testng.annotations.Test;
import org.testng.Assert;
@@ -48,14 +50,86 @@
  public static final String ACCESS_HANDLER_DN =
                                       "cn=Access Control Handler,cn=config";
  private static ByteArrayOutputStream oStream = new ByteArrayOutputStream();
  private  static ThreadLocal<Map<String,File>> tempLdifFile =
  //GLOBAL ACIs
  protected final static String G_READ_ACI =
          "(targetattr!=\"userPassword||authPassword\")" +
                  "(version 3.0; acl \"Anonymous read access\";" +
                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
  protected final static String G_SELF_MOD =
          "(targetattr=\"*\")(version 3.0; acl \"Self entry modification\";" +
                  "allow (write) userdn=\"ldap:///self\";)";
  protected final static String G_SCHEMA =
          "(target=\"ldap:///cn=schema\")(targetscope=\"base\")" +
          "(targetattr=\"attributeTypes||dITContentRules||dITStructureRules||" +
                  "ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||" +
                  "objectClasses\")" +
          "(version 3.0; acl \"User-Visible Schema Operational Attributes\";" +
                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
  protected final static String G_DSE =
          "(target=\"ldap:///\")(targetscope=\"base\")" +
               "(targetattr=\"namingContexts||supportedAuthPasswordSchemes||" +
                  "supportedControl||supportedExtension||supportedFeatures||" +
                 "supportedSASLMechanisms||vendorName||vendorVersion\")" +
        "(version 3.0; acl \"User-Visible Root DSE Operational Attributes\"; " +
                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
  protected final static String G_USER_OPS =
          "(targetattr=\"createTimestamp||creatorsName||modifiersName||" +
                  "modifyTimestamp||entryDN||entryUUID||subschemaSubentry\")" +
                 "(version 3.0; acl \"User-Visible Operational Attributes\"; " +
                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
  protected final static String G_CONTROL =
          "(targetcontrol = \"*\")" +
          "(version 3.0; acl \"Control\"; " +
                  "allow (read) userdn=\"ldap:///anyone\";)";
  private static final ByteArrayOutputStream oStream = new ByteArrayOutputStream();
  private  static final ThreadLocal<Map<String,File>> tempLdifFile =
           new ThreadLocal<Map<String,File>>();
  protected String pwdModify(String bindDn, String bindPassword,
                             String newPassword, String noOpControl,
                             String pwdPolicyControl, int rc) {
    ArrayList<String> argList=new ArrayList<String>(20);
    argList.add("-h");
    argList.add("127.0.0.1");
    argList.add("-p");
    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
    argList.add("-D");
    argList.add(bindDn);
    argList.add("-w");
    argList.add(bindPassword);
    argList.add("-c");
    argList.add(bindPassword);
    argList.add("-n");
    argList.add(newPassword);
    if(noOpControl != null) {
      argList.add("-J");
      argList.add(noOpControl);
    }
    if(pwdPolicyControl != null) {
      argList.add("-J");
      argList.add(pwdPolicyControl);
    }
    String[] args = new String[argList.size()];
    oStream.reset();
    int ret=
           LDAPPasswordModify.mainPasswordModify(argList.toArray(args),
                   false, oStream, oStream);
    Assert.assertEquals(rc, ret,  "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  protected String LDAPSearchCtrl(String bindDn, String bindPassword,
                            String proxyDN, String controlStr,
                            String base, String filter, String attr)
          throws Exception {
                            String base, String filter, String attr) {
    ArrayList<String> argList=new ArrayList<String>(20);
    argList.add("-h");
    argList.add("127.0.0.1");
@@ -90,10 +164,29 @@
    return oStream.toString();
  }
  protected String
  LDAPSearchParams(String bindDn,  String bindPassword,
                               String proxyDN, String authzid,
                               String[] attrList,
                               String base, String filter ,String attr,
                               boolean pwdPolicy, boolean reportAuthzID,
                               int rc)  {
    return _LDAPSearchParams(bindDn, bindPassword, proxyDN, authzid, attrList,
            base, filter, attr, pwdPolicy, reportAuthzID, rc);
  }
  protected String LDAPSearchParams(String bindDn, String bindPassword,
                                    String proxyDN, String authzid,
                                    String[] attrList,
                                    String base, String filter ,String attr) {
    return _LDAPSearchParams(bindDn, bindPassword, proxyDN, authzid, attrList,
            base, filter, attr, false, false, 0);
  }
  private String _LDAPSearchParams(String bindDn, String bindPassword,
                            String proxyDN, String authzid, String[] attrList,
                            String base, String filter ,String attr)
          throws Exception {
                            String base, String filter ,String attr,
                            boolean pwdPolicy, boolean reportAuthzID, int rc) {
    ArrayList<String> argList=new ArrayList<String>(20);
    argList.add("-h");
    argList.add("127.0.0.1");
@@ -118,6 +211,12 @@
        argList.add(a);
      }
    }
    if(pwdPolicy) {
      argList.add("--usePasswordPolicyControl");
    }
    if(reportAuthzID) {
      argList.add("-E");
    }
    argList.add("-b");
    argList.add(base);
    argList.add("-s");
@@ -130,11 +229,59 @@
    oStream.reset();
    int retVal =
         LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
    Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  protected void LDIFAdd(String ldif, String bindDn, String bindPassword,
                            String controlStr, int rc) throws Exception {
    _LDIFModify(ldif, bindDn, bindPassword, controlStr, true, rc);
  }
  protected void LDIFModify(String ldif, String bindDn, String bindPassword,
                            String controlStr, int rc) throws Exception {
    _LDIFModify(ldif, bindDn, bindPassword, controlStr, false, rc);
  }
  protected void LDIFModify(String ldif, String bindDn, String bindPassword)
  throws Exception {
    _LDIFModify(ldif, bindDn, bindPassword, null, false, -1);
  }
  protected void LDIFDelete(String dn, String bindDn, String bindPassword,
                            String controlStr, int rc) {
    _LDIFDelete(dn, bindDn, bindPassword, controlStr, rc);
  }
  private void _LDIFDelete(String dn, String bindDn, String bindPassword,
                           String controlStr, int rc) {
    ArrayList<String> argList=new ArrayList<String>(20);
    argList.add("-h");
    argList.add("127.0.0.1");
    argList.add("-p");
    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
    argList.add("-D");
    argList.add(bindDn);
    argList.add("-w");
    argList.add(bindPassword);
    if(controlStr != null) {
      argList.add("-J");
      argList.add(controlStr);
    }
    argList.add(dn);
    String[] args = new String[argList.size()];
    ldapDelete(argList.toArray(args), rc);
  }
  private void ldapDelete(String[] args, int rc) {
    oStream.reset();
    int retVal = LDAPDelete.mainDelete(args, false, oStream, oStream);
    Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
  }
  private void _LDIFModify(String ldif, String bindDn, String bindPassword,
                           String controlStr, boolean add,  int rc)
          throws Exception {
    File tempFile = getTemporaryLdifFile();
    TestCaseUtils.writeFile(tempFile, ldif);
@@ -147,19 +294,27 @@
    argList.add(bindDn);
    argList.add("-w");
    argList.add(bindPassword);
    if(controlStr != null) {
      argList.add("-J");
      argList.add(controlStr);
    }
    if(add) {
     argList.add("-a");
    }
    argList.add("-f");
    argList.add(tempFile.getAbsolutePath());
    String[] args = new String[argList.size()];
    ldapModify(argList.toArray(args));
    ldapModify(argList.toArray(args), rc);
  }
  protected void ldapModify(String[] args) {
  private void ldapModify(String[] args, int rc) {
    oStream.reset();
    LDAPModify.mainModify(args, false, oStream, oStream);
    int retVal =LDAPModify.mainModify(args, false, oStream, oStream);
    if(rc != -1)
       Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
  }
  protected void deleteAttrFromEntry(String dn, String attr)
  throws Exception {
  protected void deleteAttrFromEntry(String dn, String attr) throws Exception {
    StringBuilder ldif = new StringBuilder();
    ldif.append(TestCaseUtils.makeLdif(
            "dn: "  + dn,
@@ -168,6 +323,20 @@
    LDIFModify(ldif.toString(), DIR_MGR_DN, PWD);
  }
  protected static String makeModDNLDIF(String dn, String newRDN,
                                    String deleteOldRDN,
                                    String newSuperior ) {
    StringBuilder ldif = new StringBuilder();
    ldif.append("dn: ").append(dn).append(EOL);
    ldif.append("changetype: modrdn").append(EOL);
    ldif.append("newrdn: ").append(newRDN).append(EOL);
    ldif.append("deleteoldrdn: ").append(deleteOldRDN).append(EOL);
    if(newSuperior != null)
       ldif.append("newsuperior: ").append(newSuperior).append(EOL);
    ldif.append(EOL);
    return ldif.toString();
  }
  protected static String makeDelLDIF(String attr, String dn, String... acis) {
    StringBuilder ldif = new StringBuilder();
    ldif.append("dn: ").append(dn).append(EOL);
@@ -179,6 +348,16 @@
    return ldif.toString();
  }
  protected static String
  makeAddEntryLDIF(String dn, String ... lines) {
    StringBuilder ldif = new StringBuilder();
    ldif.append("dn: ").append(dn).append(EOL);
    ldif.append("changetype: add").append(EOL);
    for(String l : lines)
       ldif.append(l).append(EOL);
    ldif.append(EOL);
    return ldif.toString();
  }
  protected static String makeAddLDIF(String attr, String dn, String... acis) {
    StringBuilder ldif = new StringBuilder();
@@ -191,7 +370,7 @@
    return ldif.toString();
  }
  protected File getTemporaryLdifFile() throws IOException {
  private File getTemporaryLdifFile() throws IOException {
    Map<String,File> tempFilesForThisThread = tempLdifFile.get();
    if (tempFilesForThisThread == null) {
      tempFilesForThisThread = new HashMap<String,File>();
@@ -313,7 +492,7 @@
  }
  protected HashMap<String, String>
  getAttrMap(String resultString) throws Exception {
  getAttrMap(String resultString) {
    StringReader r=new StringReader(resultString);
    BufferedReader br=new BufferedReader(r);
    HashMap<String, String> attrMap = new HashMap<String,String>();
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -38,6 +38,7 @@
import org.opends.server.util.LDIFReader;
import org.opends.server.util.LDIFWriter;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.util.ServerConstants.*;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
@@ -307,6 +308,12 @@
  //The ACIs for the proxy tests.
  private static final String ALLOW_PROXY_CONTROL_TO_LEVEL_1=
             buildAciValue("name", "allow proxy control", "targetcontrol",
                     OID_PROXIED_AUTH_V2, "allow(read)",
                     BIND_RULE_USERDN_LEVEL_1);
  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);
@@ -1050,22 +1057,46 @@
                                       GLOBAL_ALLOW_MONITOR_TO_ADMIN_ACI,
                                       GLOBAL_ALLOW_BASE_DN_TO_LEVEL_1_ACI);
    //Global defauls
private static final String GLOBAL_ANONYMOUS_READ_ACI =
       buildGlobalAciValue("name", "Anonymous read access", "targetattr!=",
                                     "userPassword||authPassword",
                                     "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
  //Global defaults
  private static final String GLOBAL_ANONYMOUS_READ_ACI =
          buildGlobalAciValue("name", "Anonymous read access", "targetattr!=",
                  "userPassword||authPassword",
                  "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
private static final String GLOBAL_SELF_WRITE_ACI =
       buildGlobalAciValue("name", "Self entry modification", "targetattr",
                                     "*",
                                     "allow(write)", BIND_RULE_USERDN_SELF);
  private static final String GLOBAL_SELF_WRITE_ACI =
          buildGlobalAciValue("name", "Self entry modification", "targetattr",
                  "*",
                  "allow(write)", BIND_RULE_USERDN_SELF);
  private static final String GLOBAL_SCHEMA_ACI =
          buildGlobalAciValue("name", "User-Visible Schema Operational Attributes",
                  "target", "ldap:///cn=schema", "targetscope", "base",
                  "targetattr",
                  "attributeTypes||dITContentRules||dITStructureRules||ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||objectClasses",
                  "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
private static final String GLOBAL_DEFAULT_ACIS =
  private static final String GLOBAL_DSE_ACI = buildGlobalAciValue(
          "name","User-Visible Root DSE Operational Attributes",
          "target", "ldap:///", "targetscope", "base",
          "targetattr",
          "namingContexts||supportedAuthPasswordSchemes||supportedControl||supportedExtension||supportedFeatures||supportedSASLMechanisms||vendorName||vendorVersion",
          "allow(read, search, compare)",BIND_RULE_USERDN_ANYONE);
  private static final String GLOBAL_USER_OP_ATTRS_ACI = buildGlobalAciValue(
          "name", "User-Visible Operational Attributes", "targetattr",
          "createTimestamp||creatorsName||modifiersName||modifyTimestamp||entryDN||entryUUID||subschemaSubentry",
          "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
  private static final String GLOBAL_CONTROL_ACI = buildGlobalAciValue(
          "name", "Control", "targetcontrol", "*",
          "allow(read)", BIND_RULE_USERDN_ANYONE);
  private static final String GLOBAL_DEFAULT_ACIS =
                     makeAttrAddAciLdif(ATTR_AUTHZ_GLOBAL_ACI,ACCESS_HANDLER_DN,
                                        GLOBAL_ANONYMOUS_READ_ACI,
                                        GLOBAL_SELF_WRITE_ACI);
                                        GLOBAL_SELF_WRITE_ACI, GLOBAL_SCHEMA_ACI,
                                        GLOBAL_DSE_ACI, GLOBAL_USER_OP_ATTRS_ACI,
                                        GLOBAL_CONTROL_ACI);
 //ACI used to test LDAP compare.
 private static final
@@ -1102,6 +1133,10 @@
  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_CONTROL_LEVEL_1 =
                  makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_CONTROL_TO_LEVEL_1);
 private static final  String ACI_PROXY_IMPORT_MGR =
                   makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR);
@@ -1769,6 +1804,7 @@
    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_CONTROL_LEVEL_1, 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);
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
@@ -32,6 +32,7 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.annotations.AfterClass;
import org.testng.Assert;
import org.opends.server.TestCaseUtils;
import static org.opends.server.config.ConfigConstants.*;
@@ -55,11 +56,17 @@
       "(version 3.0; acl \"proxy" +  user3 + "\";" +
       "allow (proxy) userdn=\"ldap:///" + user3 + "\";)";
  //Need an ACI to allow proxy control
  String controlACI = "(targetcontrol=\"" + OID_PROXIED_AUTH_V2 + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + user3 + "\";)";
  private static final
  String rootDNACI= "(targetattr=\"" + ATTR_USER_PASSWORD + "\")" +
        "(version 3.0; acl \"pwd search, read " + rootDN + "\";" +
        "allow(read, search) userdn=\"ldap:///" + rootDN + "\";)";
  @BeforeClass
  public void setupClass() throws Exception {
    TestCaseUtils.startServer();
@@ -68,6 +75,13 @@
    addRootEntry();
  }
  @AfterClass
  public void tearDown() throws Exception {
    String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
            G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
  }
  /**
   * This test uses an ACI allowing access to the userPassword attribute, based
@@ -117,7 +131,7 @@
   */
  @Test()
  public void testAlternateProxyDNs() throws Exception {
    String aciLdif=makeAddLDIF("aci", user1, rootDNACI, proxyACI);
    String aciLdif=makeAddLDIF("aci", user1, rootDNACI, proxyACI, controlACI);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
    String adminDNResults =
            LDAPSearchParams(user3, PWD, adminDN, null, null,
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
@@ -30,10 +30,12 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterClass;
import static org.opends.server.config.ConfigConstants.*;
import org.testng.Assert;
import org.opends.server.TestCaseUtils;
import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
import java.util.HashMap;
public class GetEffectiveRightsTestCase extends AciTestCase {
@@ -86,6 +88,12 @@
          "selfwrite_add:1,selfwrite_delete:1,proxy:0";
  //ACI needed to search/read aciRights attribute.
  //Need an ACI to allow proxy control
  String controlACI = "(targetcontrol=\"" + OID_GET_EFFECTIVE_RIGHTS + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///anyone\";)";
  private static final
  String aclRightsAci = "(targetattr=\"aclRights\")" +
          "(version 3.0;acl \"aclRights access\";" +
@@ -160,10 +168,17 @@
    addEntries();
  }
    @BeforeMethod
    public void removeAcis() throws Exception {
  @AfterClass
  public void tearDown() throws Exception {
       String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
               G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
       LDIFModify(aciLdif, DIR_MGR_DN, PWD);
   }
   @BeforeMethod
   public void removeAcis() throws Exception {
        deleteAttrFromEntry("ou=People,o=test", "aci");
  }
   }
  /**
   * Test entry level using the -g param and anonymous dn as the authzid.
@@ -172,7 +187,8 @@
   */
  @Test()
  public void testAnonEntryLevelParams() throws Exception {
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAnonAci);
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAnonAci,
                               controlACI);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(DIR_MGR_DN, PWD, null, "dn:", null,
@@ -190,7 +206,8 @@
   */
  @Test()
  public void testSuEntryLevelParams() throws Exception {
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
                               controlACI);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
    aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -242,7 +259,8 @@
   */
  @Test()
   public void testSuEntryLevelCtrl() throws Exception {
     String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
     String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
                                controlACI);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -294,6 +312,8 @@
  */
 @Test()
  public void testBypassEntryLevelCtrl() throws Exception {
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test",  controlACI);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
           LDAPSearchCtrl(DIR_MGR_DN, PWD, null, OID_GET_EFFECTIVE_RIGHTS,
                   base, filter, "aclRights");
@@ -311,7 +331,8 @@
   */
  @Test()
  public void testSuAttrLevelParams() throws Exception {
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
                               controlACI);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
    aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -337,7 +358,8 @@
 */
@Test()
public void testSuAttrLevelParams2() throws Exception {
  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
                             controlACI);
  LDIFModify(aciLdif, DIR_MGR_DN, PWD);
  aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
  LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -369,7 +391,8 @@
 */
@Test()
public void testSuAttrLevelParams3() throws Exception {
  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
                            controlACI);
  LDIFModify(aciLdif, DIR_MGR_DN, PWD);
  aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
  LDIFModify(aciLdif, DIR_MGR_DN, PWD);
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -29,6 +29,7 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.annotations.AfterClass;
import org.testng.Assert;
import org.opends.server.TestCaseUtils;
import static org.opends.server.config.ConfigConstants.*;
@@ -125,6 +126,14 @@
    addEntries();
  }
  @AfterClass
  public void tearDown() throws Exception {
     String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
          G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
  }
  /**
   * Test targetattr behavior using userattr bind rule.
   *
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
New file
@@ -0,0 +1,342 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.authorization.dseecompat;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.opends.server.TestCaseUtils;
import org.opends.server.protocols.ldap.LDAPResultCode;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
/**
 * Unit test to test the targetcontrol ACI keyword.
 */
public class TargetControlTestCase extends AciTestCase {
  private static final String superUser="uid=superuser,ou=admins,o=test";
  private static final String level3User="uid=user.3,ou=People,o=test";
  private static final String newPWD="newPWD";
  private static final String level1User="uid=user.1,ou=People,o=test";
  private static final String base="uid=user.3,ou=People,o=test";
  private static final String newRDN = "uid=user.3x";
  private static final String newSup="ou=new,o=test";
  private static final String newDN="uid=user.4," + base;
  private static final String peopleBase="ou=People,o=test";
  private static final String adminBase="ou=Admins,o=test";
  private static final String newPeopleDN="uid=user.4," + peopleBase;
  private static final String newAdminDN="uid=user.4," + adminBase;
  @BeforeClass
  public void setupClass() throws Exception {
    TestCaseUtils.startServer();
    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
    addEntries();
  }
  @AfterClass
  public void tearDown() throws Exception {
       String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
               G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
       LDIFModify(aciLdif, DIR_MGR_DN, PWD);
   }
  private static final String[] newEntry = new String[] {
    "objectClass: top",
    "objectClass: person",
    "objectClass: organizationalPerson",
    "objectClass: inetOrgPerson",
    "uid: john.doe",
    "givenName: John",
    "sn: Doe",
    "cn: John Doe",
    "mail: john.doe@example.com",
    "userPassword: password",
  };
  //Valid targetcontrol statements. Not the complete ACI.
  @DataProvider(name = "validStatements")
  public Object[][] valids() {
    return new Object[][] {
            {"1.3.6.1.4.1.42.2.27.8.5.1"},
            {"2.16.840.1.113730.3.4.18"},
            {"*"},
    };
  }
   //Invalid targetcontrol statements. Not the complete ACI.
  @DataProvider(name = "invalidStatements")
  public Object[][] invalids() {
    return new Object[][] {
            {"1.3.6.1.4.1.42.2.27..8.5.1"},
            {"2.16.840.1.113730.3.XXX.18"},
            {"2.16.840.1.113730.*.4.18"},
            {"2.16.840,1.113730.3.4.18"},
            {"+"},
    };
  }
  private static final
  String ALLOW_ALL = "(targetattr=\"*\")" +
          "(version 3.0;acl \"aclRights access\";" +
          "allow (all) " +
          "userdn=\"ldap:///self\";)";
  private static final
  String aclRightsAci = "(targetattr=\"aclRights\")" +
          "(version 3.0;acl \"aclRights access\";" +
          "allow (search, read) " +
          "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)";
 //Disallow all controls with wild-card.
  private static final
  String controlNotWC = "(targetcontrol!=\"" + "*" + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + superUser + "\";)";
  //Allow all controls with wild-card.
  private static final
  String controlWC = "(targetcontrol=\"" + "*" + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + superUser + "\";)";
  //People branch can do any control but geteffectiverights assertion control.
  private static final
  String controlPeople = "(targetcontrol!=\"" +
          OID_GET_EFFECTIVE_RIGHTS + "\")" +
          "(target=\"ldap:///" + peopleBase + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
  //Admin branch can only do geteffectiverights control.
  private static final
  String controlAdmin = "(targetcontrol=\"" + OID_GET_EFFECTIVE_RIGHTS + "\")" +
          "(target=\"ldap:///" + adminBase + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
  //Allow either reportauthzID or passwordpolicy controls. Used in the
  //bind tests.
  private static final
  String pwdControls =
          "(targetcontrol=\"" + OID_AUTHZID_REQUEST + "||" +
          OID_PASSWORD_POLICY_CONTROL + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
  //Allow either no-op or passwordpolicy controls. Used in the
  //ext op tests.
  private static final
  String extOpControls =
          "(targetcontrol=\"" + OID_LDAP_NOOP_OPENLDAP_ASSIGNED + "||" +
          OID_PASSWORD_POLICY_CONTROL + "\")" +
          "(version 3.0; acl \"control\";" +
          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
  /**
   * Test valid targetcontrol statements.
   *
   * @param statement The targetcontrol statement to attempt to decode.
   * @throws AciException  If an unexpected result happens.
   */
  @Test(dataProvider = "validStatements")
  public void testValidStatements(String statement) throws AciException {
      TargetControl.decode(EnumTargetOperator.EQUALITY, statement);
  }
  /**
   * Test invalid targetcontrol statements.
   *
   * @param statement The targetcontrol statement to attempt to decode.
   * @throws Exception  If an unexpected result happens.
   */
  @Test(expectedExceptions= AciException.class, dataProvider="invalidStatements")
  public void testInvalidStatements(String statement)  throws Exception {
    try {
      TargetControl.decode(EnumTargetOperator.EQUALITY,statement);
    } catch (AciException e) {
      throw e;
    } catch (Exception e) {
      System.out.println(
              "Invalid targetcontrol  <" + statement +
              "> threw wrong exception type.");
      throw e;
    }
    throw new RuntimeException(
            "Invalid targetcontrol <" + statement +
            "> did not throw an exception.");
  }
  /**
   * Test access to extended op controls (no-op and userPasswordPolicy).
   *
   * @throws Exception If an unexpected result is returned.
   */
  @Test()
  public void testExtendOpControls() throws Exception {
   String pwdLdifs =
        makeAddLDIF("aci", peopleBase, extOpControls, ALLOW_ALL);
    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
    String noOpCtrlStr=OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true";
    //This pwd change should return no-op since the no-op control is
    //specified and it is allowed for authorization dn.
    pwdModify(level3User, PWD, newPWD, noOpCtrlStr, null,
            LDAPResultCode.NO_OPERATION);
    //This pwd change should fail even though the no-op is specified, since
    //since the no-op control is not allowed for this authorization dn.
    pwdModify(superUser, PWD, newPWD, noOpCtrlStr, null,
            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    deleteAttrFromEntry(peopleBase, "aci");
  }
  /**
   * Test access to bind controls (reportAuthzID and usePasswordPolicy).
   *
   * @throws Exception If an unexpected result is returned.
   */
  @Test()
  public void testBindControl() throws Exception {
    String pwdLdifs =
            makeAddLDIF("aci", peopleBase, pwdControls, ALLOW_ALL);
    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
    //The bind operation control access is based on the  bind DN so this
    //should succeed since both pwd policy and authzID control are allowed on
    //ou=people, o=test suffix.
    LDAPSearchParams(level3User, PWD, null, null, null,
            superUser, filter, "aclRights mail description", true,
            false, 0);
    LDAPSearchParams(level3User, PWD, null, null, null,
            superUser, filter, "aclRights mail description", true,
            true, 0);
    //This should fail since the both controls are not allowed for the
    //ou=admins, o=test suffix.
    LDAPSearchParams(superUser, PWD, null, null, null,
            superUser, filter, "aclRights mail description", true,
            true, LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    deleteAttrFromEntry(peopleBase, "aci");
  }
  /**
   * Test target from global ACI level. Two global ACIs are added, one allowing
   * all controls except geteffective rights to the ou=people, o=test
   * suffix. The other ACI only allows the geteffectiverights control on
   * the ou=admin, o=test suffix. Comments in method should explain more
   * what operations and controls are attempted.
   *
   * @throws Exception If an unexpected result happens.
   */
  @Test()
  public void testGlobalTargets() throws Exception {
    String globalControlAcis=
            makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
                    controlAdmin, controlPeople);
    LDIFModify(globalControlAcis, DIR_MGR_DN, PWD);
    //Fails because geteffectiverights control not allowed on
    //ou=people, o=test
    LDAPSearchParams(level3User, PWD, null,
            "dn: " + level1User, null,
            level1User, filter, "aclRights mail description",
            false, false, LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    //Ok because geteffectiverights control is allowed on
    //ou=admin, o=test
    LDAPSearchParams(level3User, PWD, null,
            "dn: " + level1User, null,
            superUser, filter, "aclRights mail description",
            false, false, 0);
    String controlStr=OID_LDAP_ASSERTION + ":true:junk";
    //Test add to ou=people, o=test with assertion control,
    //should get protocol error since this control is allowed but value is
    //junk.
    String addEntryLDIF=makeAddEntryLDIF(newPeopleDN, newEntry);
    LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
            LDAPResultCode.PROTOCOL_ERROR);
    //Test add to ou=admin, o=test with assertion control,
    //should get access denied since this control is not allowed.
    String addEntryLDIF1=makeAddEntryLDIF(newAdminDN, newEntry);
    LDIFAdd(addEntryLDIF1, superUser, PWD, controlStr,
            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
  }
  /**
   * Test wildcard access. First test "targetcontrol != *"
   * expression. Should all be access denied. Remove that ACI and add
   * "targetcontrol = *" expression. Use assertion control with bad filter,
   * all should return protocol error (modify, add, delete, modifyDN). Search
   * with geteffectiverights should succeed.
   *
   * @throws Exception If an unexpected result happens.
   */
  @Test()
  public void testWildCard() throws Exception {
    String aciDeny=makeAddLDIF("aci", base, controlNotWC);
    String aciRight=makeAddLDIF("aci", base, aclRightsAci);
    LDIFModify(aciDeny, DIR_MGR_DN, PWD);
    LDAPSearchParams(superUser, PWD, null,
            "dn: " + superUser, null,
            base, filter, "aclRights mail description", false, false,
            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    LDIFModify(aciRight, superUser, PWD, OID_LDAP_READENTRY_PREREAD,
            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    deleteAttrFromEntry (base, "aci");
    String aciAllow=makeAddLDIF("aci", base, controlWC, ALLOW_ALL);
    LDIFModify(aciAllow, DIR_MGR_DN, PWD);
    //Search with geteffectiverights control.
    LDAPSearchParams(superUser, PWD, null,
            "dn: " + superUser, null,
            base, filter, "aclRights mail description");
    String controlStr=OID_LDAP_ASSERTION + ":true:junk";
    //Attempt modify. Protocol error means we  passed access control
    LDIFModify(aciRight, superUser, PWD, controlStr ,
            LDAPResultCode.PROTOCOL_ERROR);
    //Attempt add, protocol error means we  passed access control
    String addEntryLDIF=makeAddEntryLDIF(newDN, newEntry);
    LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
            LDAPResultCode.PROTOCOL_ERROR);
    //Attempt delete. Protocol error means we  passed access control.
    LDIFDelete(base, superUser, PWD, controlStr,
            LDAPResultCode.PROTOCOL_ERROR);
    String modDNLDIF=makeModDNLDIF(base, newRDN , "0", newSup);
    //Attempt modify DN. Protocol error means we  passed access control.
    LDIFModify(modDNLDIF, superUser, PWD, controlStr ,
            LDAPResultCode.PROTOCOL_ERROR);
    deleteAttrFromEntry(base, "aci");
  }
}