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

dugan
14.12.2007 2c6d8da210ec30d9cf99be6e7b75c28ed476b742
Add support for '+' all attributes description in targetattrs expression, with missing files from previous commit. See issue 1779 for more info.
8 files modified
617 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java 50 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java 75 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java 27 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java 48 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java 57 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java 167 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java 31 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java 162 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -110,11 +110,12 @@
    /**
     * Regular expression that graciously matches an attribute type name. Must
     * begin with an ASCII letter or digit, and contain only ASCII letters,
     * digit characters, hyphens, semi-colons and underscores.
     * They are case insensitive.
     * digit characters, hyphens, semi-colons and underscores. It also allows
     * the special shorthand characters "*" for all user attributes and "+" for
     * all operational attributes.
     */
    public  static final String ATTR_NAME =
              "((?i)[a-z\\d]{1}[[a-z]\\d-_.;]*(?-i))";
              "((?i)[a-z\\d]{1}[[a-z]\\d-_.;]*(?-i)|\\*{1}|\\+{1})";
    /**
      * Regular expression matching a LDAP URL.
@@ -150,10 +151,18 @@
    /**
     * Regular expression the matches "*".
     */
    public static final String ALL_ATTRS_WILD_CARD = ZERO_OR_MORE_WHITESPACE +
    public static final String ALL_USER_ATTRS_WILD_CARD =
            ZERO_OR_MORE_WHITESPACE +
                                           "\\*" + ZERO_OR_MORE_WHITESPACE;
    /**
     * Regular expression the matches "+".
     */
    public static final String ALL_OP_ATTRS_WILD_CARD =
            ZERO_OR_MORE_WHITESPACE +
                    "\\+" + ZERO_OR_MORE_WHITESPACE;
    /**
     * ACI_ADD is used to set the container rights for a LDAP add operation.
     */
    public static final int ACI_ADD = 0x0020;
@@ -265,15 +274,38 @@
     * evaluation if the flag is ACI_ATTR_STAR_MATCHED (all attributes match)
     * and the attribute type is not operational.
     */
    public static final int ACI_ATTR_STAR_MATCHED = 0x0008;
    public static final int ACI_USER_ATTR_STAR_MATCHED = 0x0008;
    /**
     * ACI_FOUND_ATTR_RULE is the flag set when the evaluation reason of a
     * ACI_FOUND_USER_ATTR_RULE is the flag set when the evaluation reason of a
     * AciHandler.maysend ACI_READ access evaluation was the result of an
     * ACI targetattr specific attribute expression
     * (targetattr="some attribute type") target match.
     * ACI targetattr specific user attribute expression
     * (targetattr="some user attribute type") target match.
     */
    public static final int ACI_FOUND_ATTR_RULE = 0x0010;
    public static final int ACI_FOUND_USER_ATTR_RULE = 0x0010;
    /**
     * ACI_OP_ATTR_PLUS_MATCHED is the flag set when the evaluation reason of a
     * AciHandler.maysend ACI_READ access evaluation was the result of an
     * ACI targetattr all operational attributes expression (targetattr="+")
     * target match. For this flag to be set, there must be only one
     * ACI matching.
     *
     * This flag and ACI_FOUND_OP_ATTR_RULE are used in the
     * AciHandler.filterEntry.accessAllowedAttrs method to skip access
     * evaluation if the flag is ACI_OP_ATTR_PLUS_MATCHED (all operational
     * attributes match) and the attribute type is operational.
     */
    public static final int ACI_OP_ATTR_PLUS_MATCHED = 0x0004;
    /**
     * ACI_FOUND_OP_ATTR_RULE is the flag set when the evaluation reason of a
     * AciHandler.maysend ACI_READ access evaluation was the result of an
     * ACI targetattr specific operational attribute expression
     * (targetattr="some operational attribute type") target match.
     */
    public static final int ACI_FOUND_OP_ATTR_RULE = 0x0020;
    /**
     * ACI_NULL is used to set the container rights to all zeros. Used
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -280,12 +280,20 @@
            this.authzid=getEffectiveRightsControl.getAuthzDN();
          this.specificAttrs=getEffectiveRightsControl.getAttributes();
        }
        //If the ACI evaluated because of an Targetattr="*", then the
        //If an ACI evaluated because of an Targetattr="*", then the
        //AciHandler.maySend method signaled this via adding this attachment
        //string.
        String allAttrs=(String)operation.getAttachment(ALL_ATTRS_MATCHED);
        if(allAttrs != null)
          evalAllAttributes = ACI_ATTR_STAR_MATCHED;
        String allUserAttrs=
                  (String)operation.getAttachment(ALL_USER_ATTRS_MATCHED);
        if(allUserAttrs != null)
          evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED;
        //If an ACI evaluated because of an Targetattr="+", then the
        //AciHandler.maySend method signaled this via adding this attachment
        //string.
        String allOpAttrs=(String)operation.getAttachment(ALL_OP_ATTRS_MATCHED);
        if(allOpAttrs != null)
          evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED;
        //The AciHandler.maySend method also adds the full attribute version of
        //the resource entry in this attachment.
        fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
@@ -823,43 +831,74 @@
  /**
   * {@inheritDoc}
   */
  public  void setACIEvalAttributesRule(int v) {
  public  void setEvalUserAttributes(int v) {
    if(operation instanceof SearchOperation && (rights == ACI_READ)) {
      if(v == ACI_FOUND_ATTR_RULE) {
        evalAllAttributes |= ACI_FOUND_ATTR_RULE;
        evalAllAttributes &= ~ACI_ATTR_STAR_MATCHED;
      if(v == ACI_FOUND_USER_ATTR_RULE) {
        evalAllAttributes |= ACI_FOUND_USER_ATTR_RULE;
        evalAllAttributes &= ~ACI_USER_ATTR_STAR_MATCHED;
      } else
        evalAllAttributes |= Aci.ACI_ATTR_STAR_MATCHED;
        evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED;
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean hasACIEvalAttributes() {
    return (evalAllAttributes & ACI_FOUND_ATTR_RULE) == ACI_FOUND_ATTR_RULE;
  public  void setEvalOpAttributes(int v) {
    if(operation instanceof SearchOperation && (rights == ACI_READ)) {
      if(v == ACI_FOUND_OP_ATTR_RULE) {
        evalAllAttributes |= ACI_FOUND_OP_ATTR_RULE;
        evalAllAttributes &= ~ACI_OP_ATTR_PLUS_MATCHED;
      } else
        evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED;
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean hasEvalUserAttributes() {
    return (evalAllAttributes & ACI_FOUND_USER_ATTR_RULE) ==
            ACI_FOUND_USER_ATTR_RULE;
  }
  /**
   * Return true if the evaluating ACI either contained a targetattr all
   * attributes rule matched only.
   * {@inheritDoc}
   */
  public boolean hasEvalOpAttributes() {
    return (evalAllAttributes & ACI_FOUND_OP_ATTR_RULE) ==
            ACI_FOUND_OP_ATTR_RULE;
  }
  /**
   * Return true if the evaluating ACI contained a targetattr all
   * user attributes rule match.
   *
   * @return  True if the above condition was seen.
   **/
  public boolean hasACIAllAttributes() {
    return (evalAllAttributes & ACI_ATTR_STAR_MATCHED) == ACI_ATTR_STAR_MATCHED;
  public boolean hasAllUserAttributes() {
    return (evalAllAttributes & ACI_USER_ATTR_STAR_MATCHED) ==
            ACI_USER_ATTR_STAR_MATCHED;
  }
  /**
   * Return true if the evaluating ACI contained a targetattr all
   * operational attributes rule match.
   *
   * @return  True if the above condition was seen.
   **/
    public boolean hasAllOpAttributes() {
    return (evalAllAttributes & ACI_OP_ATTR_PLUS_MATCHED) ==
            ACI_OP_ATTR_PLUS_MATCHED;
  }
  /**
   * {@inheritDoc}
   */
  public void clearACIEvalAttributesRule(int v) {
  public void clearEvalAttributes(int v) {
    if(v == 0)
      evalAllAttributes=0;
    else
      evalAllAttributes &= ~v;
  }
}
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -98,10 +98,16 @@
    public static String ALL_ATTRS_RESOURCE_ENTRY = "allAttrsResourceEntry";
    /**
     * String used to indicate that the evaluating ACI had a all attributes
     * String used to indicate that the evaluating ACI had a all user attributes
     * targetattr match (targetattr="*").
     */
     public static String ALL_ATTRS_MATCHED = "allAttrsMatched";
     public static String ALL_USER_ATTRS_MATCHED = "allUserAttrsMatched";
    /**
     * String used to indicate that the evaluating ACI had a all operational
     * attributes targetattr match (targetattr="+").
     */
     public static String ALL_OP_ATTRS_MATCHED = "allOpAttrsMatched";
    /**
     * This constructor instantiates the ACI handler class that performs the
@@ -606,13 +612,14 @@
      Entry e=container.getResourceEntry();
      List<AttributeType> typeList=getAllAttrs(e);
      for(AttributeType attrType : typeList) {
        if(container.hasACIAllAttributes() && !attrType.isOperational())
            if(container.hasAllUserAttributes() && !attrType.isOperational())
                continue;
            if(container.hasAllOpAttributes() && attrType.isOperational())
          continue;
        container.setCurrentAttributeType(attrType);
        if(!accessAllowed(container)) {
            if(!accessAllowed(container))
          e.removeAttribute(attrType);
        }
      }
      return container.getSearchResultEntry();
    }
@@ -916,12 +923,16 @@
            ret=false;
          }
          if (ret) {
              operationContainer.clearACIEvalAttributesRule(ACI_NULL);
              operationContainer.clearEvalAttributes(ACI_NULL);
              operationContainer.setRights(ACI_READ);
              ret=accessAllowedEntry(operationContainer);
            if(ret) {
              if(!operationContainer.hasACIEvalAttributes())
                operation.setAttachment(ALL_ATTRS_MATCHED, ALL_ATTRS_MATCHED);
              if(!operationContainer.hasEvalUserAttributes())
                operation.setAttachment(ALL_USER_ATTRS_MATCHED,
                        ALL_USER_ATTRS_MATCHED);
              if(!operationContainer.hasEvalOpAttributes())
                operation.setAttachment(ALL_OP_ATTRS_MATCHED,
                        ALL_OP_ATTRS_MATCHED);
            }
          }
      }
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -168,38 +168,64 @@
  /**
   * This method toggles a mask that indicates that access checking of
   * individual non-operational attributes may or may not be skipped depending
   * on if there is a single ACI containing a targetattr all attributes  rule
   * (targetattr="*").
   * individual user attributes may or may not be skipped depending
   * on if there is a single ACI containing a targetattr all user
   * attributes rule (targetattr="*").
   *
   * The only case where individual non-operational attribute access checking
   * The only case where individual user attribute access checking
   * can be skipped, is when a single ACI matched using a targetattr
   * all attributes rule.
   * all user attributes rule and the attribute type being check is not
   * operational.
   *
   * @param v  The mask to this value.
   */
  void setACIEvalAttributesRule(int v);
  void setEvalUserAttributes(int v);
  /**
   * This method toggles a mask that indicates that access checking of
   * individual operational attributes may or may not be skipped depending
   * on if there is a single ACI containing a targetattr all operational
   * attributes rule (targetattr="+").
   *
   * The only case where individual operational attribute access checking
   * can be skipped, is when a single ACI matched using a targetattr
   * all operational attributes rule and the attribute type being check is
   * operational.
   *
   * @param v  The mask to this value.
   */
  void setEvalOpAttributes(int v);
  /**
   * Return true if the evaluating ACI either contained an explicitly defined
   * attribute type in a targeattr target rule or both a targetattr all
   * attributes rule matched and a explictly defined targetattr target rule
   * user attribute type in a targeattr target rule or both a targetattr all
   * user attributes rule matched and a explictly defined targetattr target rule
   * matched.
   *
   * @return  True if the above condition was seen.
   */
    boolean hasACIEvalAttributes();
    boolean hasEvalUserAttributes();
  /**
   * Return true if the evaluating ACI either contained an explicitly defined
   * operational attribute type in a targeattr target rule or both a targetattr
   * all operational attributes rule matched and a explictly defined targetattr
   * target rule matched.
   *
   * @return  True if the above condition was seen.
   */
    boolean hasEvalOpAttributes();
  /**
   * Used to clear the mask used to detect if access checking needs to be
   * performed on individual non-operational attributes types. The specified
   * performed on individual attributes types. The specified
   * value is cleared from the mask or if the value equals 0 the mask is
   * completely cleared.
   *
   * @param v  The flag to clear or 0 to set the mask to 0.
   */
    public void clearACIEvalAttributesRule(int v);
    public void clearEvalAttributes(int v);
}
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -413,20 +413,7 @@
            boolean isFirstAttr=targetMatchCtx.isFirstAttribute();
            if((a != null) && (targets.getTargetAttr() != null))  {
             ret=TargetAttr.isApplicable(a,targets.getTargetAttr());
             targetMatchCtx.clearACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED);
             /*
               If a explicitly defined targetattr's match rule has not
               been seen (~ACI_FOUND_ATTR_RULE) and the current attribute type
               is applicable because of a targetattr all attributes rule match,
               set a flag to indicate this situation (ACI_ATTR_STAR_MATCHED).
               Else the attributes is applicable because it is operational or
               not a targetattr's all attribute match.
              */
             if(ret && targets.getTargetAttr().isAllAttributes() &&
                !targetMatchCtx.hasACIEvalAttributes())
               targetMatchCtx.setACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED);
              else
                targetMatchCtx.setACIEvalAttributesRule(ACI_FOUND_ATTR_RULE);
              setEvalAttributes(targetMatchCtx,targets,ret);
            } else if((a != null) || (targets.getTargetAttr() != null)) {
                if((aci.hasRights(skipRights)) &&
                                                (skipRightsHasRights(rights)))
@@ -563,4 +550,46 @@
        }
        return ret;
    }
    /**
     * The method is used to try and determine if a targetAttr expression that
     * is applicable has a '*' (or '+' operational attributes) token or if it
     * was applicable because of a specific attribute type declared in the
     * targetattrs expression (i.e., targetattrs=cn).
     *
     *
     * @param ctx  The ctx to check against.
     * @param targets The targets part of the ACI.
     * @param ret  The is true if the ACI has already been evaluated to be
     *             applicable.
     */
    private static
    void setEvalAttributes(AciTargetMatchContext ctx, AciTargets targets,
                           boolean ret) {
        ctx.clearEvalAttributes(ACI_USER_ATTR_STAR_MATCHED);
        ctx.clearEvalAttributes(ACI_OP_ATTR_PLUS_MATCHED);
        /*
         If an applicable targetattr's match rule has not
         been seen (~ACI_FOUND_OP_ATTR_RULE or ~ACI_FOUND_USER_ATTR_RULE) and
         the current attribute type is applicable because of a targetattr all
         user (or operational) attributes rule match,
         set a flag to indicate this situation (ACI_USER_ATTR_STAR_MATCHED or
         ACI_OP_ATTR_PLUS_MATCHED). This check also catches the following case
         where the match was by a specific attribute type (either user or
         operational) and the other attribute type has an all attribute token.
         For example, the expression is: (targetattrs="cn || +) and the current
         attribute type is cn.
        */
        if(ret && targets.getTargetAttr().isAllUserAttributes() &&
                !ctx.hasEvalUserAttributes())
          ctx.setEvalUserAttributes(ACI_USER_ATTR_STAR_MATCHED);
        else
          ctx.setEvalUserAttributes(ACI_FOUND_USER_ATTR_RULE);
        if(ret && targets.getTargetAttr().isAllOpAttributes() &&
                !ctx.hasEvalOpAttributes())
          ctx.setEvalOpAttributes(ACI_OP_ATTR_PLUS_MATCHED);
        else
          ctx.setEvalOpAttributes(ACI_FOUND_OP_ATTR_RULE);
    }
}
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
@@ -45,9 +45,14 @@
    private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
    /*
     * Flags that is set if all attributes pattern seen "*".
     * Flags that is set if all user attributes pattern seen "*".
     */
    private boolean allAttributes = false ;
    private boolean allUserAttributes = false ;
    /*
     * Flags that is set if all operational attributes pattern seen "+".
     */
    private boolean allOpAttributes = false ;
    /*
     * HashSet of the attribute types parsed by the constructor.
@@ -73,18 +78,21 @@
     * @param operator The operation enumeration of the targetattr
     * expression (=, !=).
     * @param attrString A string representing the attributes specified in
     * the targetattr expression (ie, dn || cn).
     * the targetattr expression (ie, dn || +).
     * @throws AciException If the attrs string is invalid.
     */
    private TargetAttr(EnumTargetOperator operator, String attrString)
    throws AciException {
        this.operator = operator;
        if (attrString != null) {
            if (Pattern.matches(ALL_ATTRS_WILD_CARD, attrString) ){
                allAttributes = true ;
            } else {
            if (Pattern.matches(ALL_USER_ATTRS_WILD_CARD, attrString) )
                allUserAttributes = true ;
            else  if (Pattern.matches(ALL_OP_ATTRS_WILD_CARD, attrString) )
                allOpAttributes = true ;
            else {
                if (Pattern.matches(ZERO_OR_MORE_WHITESPACE, attrString)){
                    allAttributes = false;
                    allUserAttributes = false;
                    allOpAttributes=false;
                } else {
                    if (Pattern.matches(attrListRegex, attrString)) {
                        // Remove the spaces in the attr string and
@@ -95,25 +103,9 @@
                         attrString.replaceAll(ZERO_OR_MORE_WHITESPACE, "");
                        String[] attributeArray=
                             separatorPattern.split(attrString);
                        //Add each element of array to attributes HashSet
                        //after converting it to AttributeType.
                        arrayToAttributeTypes(attributeArray);
                       //Must be either all operational attrs or all user attrs,
                       //but not both.
                        if(!opAttributes.isEmpty() && !attributes.isEmpty()) {
                            int msgID =
                             MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR;
                            String message = getMessage(msgID, attrString);
                            throw new AciException(msgID, message);
                        }
                        //Inequality not allowed with operational attrs.
                        if(!opAttributes.isEmpty() &&
                            operator.equals(EnumTargetOperator.NOT_EQUALITY)) {
                            int msgID =
                               MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY;
                            String message = getMessage(msgID, attrString);
                            throw new AciException(msgID, message);
                        }
                        //Add each element of array to appropriate HashSet
                        //after conversion to AttributeType.
                        arrayToAttributeTypes(attributeArray, attrString);
                    } else {
                      int msgID =
                         MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION;
@@ -126,14 +118,37 @@
    }
    /**
     * Converts each element of an array of attribute type strings
     * to attribute types and adds them to either the attributes HashSet or
     * the operational attributes HashSet if they are operational.
     * Converts each element of an array of attribute strings
     * to attribute types and adds them to either the user attributes HashSet or
     * the operational attributes HashSet. Also, scan for the shorthand tokens
     * "*" for all user attributes and "+" for all operational attributes.
     *
     * @param attributeArray The array of attribute type strings.
     * @param attrStr String used in error message if an Aci Exception
     *                is thrown.
     * @throws AciException If the one of the attribute checks fails.
     */
    private void arrayToAttributeTypes(String[] attributeArray) {
    private void arrayToAttributeTypes(String[] attributeArray, String attrStr)
            throws AciException {
        for (int i=0, n=attributeArray.length; i < n; i++) {
            String attribute=attributeArray[i].toLowerCase();
            if(attribute.equals("*")) {
                if(!allUserAttributes)
                    allUserAttributes=true;
                else {
                    int msgID = MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN;
                    String message = getMessage(msgID, attrStr);
                    throw new AciException(msgID, message);
                }
            } else if(attribute.equals("+")) {
                if(!allOpAttributes)
                    allOpAttributes=true;
                else {
                    int msgID = MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN;
                    String message = getMessage(msgID, attrStr);
                    throw new AciException(msgID, message);
                }
            } else {
            AttributeType attributeType;
            if((attributeType =
                    DirectoryServer.getAttributeType(attribute)) == null)
@@ -145,6 +160,7 @@
            attributes.add(attributeType);
        }
    }
    }
    /**
     * Returns the operator enumeration of the targetattr expression.
@@ -159,8 +175,18 @@
     * targetattr="*" or targetattr != "*".
     * @return True if all attributes was seen.
     */
    public boolean isAllAttributes() {
        return allAttributes;
    public boolean isAllUserAttributes() {
        return allUserAttributes;
    }
    /**
     * This flag is set if the parsing code saw:
     * targetattr="+" or targetattr != "+".
     * @return True if all attributes was seen.
     */
    public boolean isAllOpAttributes() {
        return allOpAttributes;
    }
    /**
@@ -195,67 +221,64 @@
    }
    /**
     * Perform two checks to see if a specified attribute type is applicable.
     * First, check the targetAttr's isAllAttributes() boolean. The
     * isAllAttributes boolean is set true when the string:
     * Performs test to see if the specified is applicable to the specified
     * TargetAttr. First a check if the TargetAttr parsing code saw an
     * expression like:
     *
     *       targetattrs="*"
     *  (targetattrs="+ || *), (targetattrs != "* || +)
     *
     * is  seen when an ACI is parsed.  This boolean only applies to
     * non-operational attribute types. If the attribute type being evaluated
     * and the isAllAttributes is true, then the evaluation will return false
     * because operational attributes must be explicity defined.
     * where both shorthand tokens where parsed. IF so then the attribute type
     * matches automatically (or not matches if NOT_EQUALITY).
     *
     * If the isAllAttributes boolean is true (and the attribute is
     * non-operational), the second check is skipped and the TargetAttr's
     * operator is checked to see if the method should return false
     * (NOT_EQUALITY) instead of true.
     * If there isn't a match, then the method evalAttrType is called to further
     * evaluate the attribute type and targetAttr combination.
     *
     * If the isAllAttributes boolean is false, then the attribute type is
     * checked to see if it is operational. If it is, then the operational
     * HashSet is searched to see if it contains the operational attribute
     * type. If it is found then true is returned, else false is returned
     * if it isn't found. The NOT_EQUALITY operator is invalid for operational
     * attribute types and is not checked.
     *
     * If the attribute is not operational,  then the TargeAttr's user
     * attribute type HashSet is searched to see if it contains the
     * specified attribute type. That result could be negated depending
     * on if the TargetAttr's operator is NOT_EQUALITY.
     *
     * @param a The attribute type to evaluate.
     * @param targetAttr The ACI's TargetAttr class to evaluate against.
     * @return The boolean result of the above tests and application
     * TargetAttr's operator value applied to the test result.
     */
    public static boolean isApplicable(AttributeType a,
                                       TargetAttr targetAttr) {
      boolean ret;
      if(targetAttr.isAllAttributes()) {
        //If it is an operational attribute, then access is denied for all
        //attributes wild-card. Operational attributes must be
        // explicitly defined and cannot be negated.
        if(a.isOperational()) {
          ret=false;
        } else
        if(targetAttr.isAllUserAttributes() && targetAttr.isAllOpAttributes()) {
          ret =
             !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
      }  else {
        ret=false;
          HashSet<AttributeType> attributes=targetAttr.getAttributes();
          HashSet<AttributeType> opAttributes=targetAttr.getOpAttributes();
           //Check if the attribute is operational, if so check the
           //operation HashSet.
        } else
            ret=evalAttrType(a, targetAttr);
        return ret;
    }
    /**
     * First check is to see if the attribute type is operational. If so then
     * a match is true if the allOpAttributes boolean is true or if the
     * attribute type is found in the operational attributes HashSet.
     *
     * Second check is similar to above, except the user attributes boolean
     * and HashSet is examined. Both results can be negated if the expression
     * operator is NOT_EQUALITT).
     *
     * @param a The attribute type to evaluate.
     * @param targetAttr The targetAttr to apply to the attribute type.
     * @return True if the attribute type is applicable to the targetAttr.
     */
    private static
    boolean evalAttrType(AttributeType a, TargetAttr targetAttr) {
        boolean ret=false;
           if(a.isOperational()) {
             if(opAttributes.contains(a))
            if(targetAttr.isAllOpAttributes() ||
                    targetAttr.opAttributes.contains(a))
               ret=true;
         } else {
            if(attributes.contains(a))
            if(targetAttr.isAllUserAttributes() ||
                    targetAttr.attributes.contains(a))
              ret=true;
        }
            if(targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY))
              ret = !ret;
          }
       }
      return ret;
    }
}
opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -742,20 +742,13 @@
    /**
   * The message ID for the message that will be used if a targetattr
   * keyword expression contains both operational and user attribute
   * types. This takes one argument, which is the targetattr expression string.
   * keyword expression contains an error when a each token in an targetattr
   * expression was parsed. This takes one argument, which is the expression
   * string that caused the error.
   */
  public static final int MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR =
  public static final int MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN =
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 74;
  /**
   * The message ID for the message that will be used if a targetattr
   * keyword expression performs both an inequality operation using
   * operational attribute types. This takes one argument, which is the
   * targetattr expression string.
   */
  public static final int MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY =
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 75;
  /**
   * The message ID for the message that will be used if a roledn
@@ -763,7 +756,7 @@
   * This takes one argument, which is the roledn expression string.
   */
  public static final int MSGID_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED =
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 76;
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 75;
   /**
   * The message ID for the message that will be used if there are ACI decode
@@ -772,7 +765,7 @@
   * exception.
   */
  public static final int MSGID_ACI_SERVER_DECODE_FAILED =
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 77;
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 76;
   /**
@@ -781,7 +774,7 @@
   * causing the server is being put in lockdown mode. The takes no arguments.
   */
  public static final int MSGID_ACI_ENTER_LOCKDOWN_MODE =
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 78;
       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 77;
    /**
@@ -1206,17 +1199,11 @@
          "Selfwrite check skipped because an attribute \"%s\" with a " +
          "distinguished name syntax was not a valid DN");
      registerMessage(MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR,
      registerMessage(MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN,
              "The provided Access Control Instruction (ACI) " +
              "targetattr expression value \"%s\" is invalid because" +
              " the expression contains both operational attribute types" +
              " and user attribute types");
              " the expression contains invalid or duplicate tokens");
      registerMessage(MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY,
              "The provided Access Control Instruction (ACI) " +
              "targetattr expression value \"%s\" is invalid because" +
              " the expression performs an inequality operation using " +
              "operational attribute types");
      registerMessage(MSGID_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED,
              "The provided Access Control Instruction (ACI) expression " +
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -44,9 +44,46 @@
  private static final String user3="uid=user.3,ou=People,o=test";
  public  static final String aciFilter = "(aci=*)";
  private static final
  String starAciAttrs = "(targetattr=\"* || aci\")" +
          "(version 3.0;acl \"read/search all user, aci op\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
  private static final
  String ocOpAttrs = "(targetattr=\"objectclass || +\")" +
          "(version 3.0;acl \"read/search all op, oc user\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
  private static final
  String OpSrchAttrs = "(targetattr=\"sn || uid || +\")" +
          "(version 3.0;acl \"read/search all op, sn uid user\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
  private static final
  String allAttrs = "(targetattr=\"* || +\")" +
          "(version 3.0;acl \"read/search all user and all op lattr\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
  private static final
  String allOpAttrAci1 = "(targetattr=\"+\")" +
          "(version 3.0;acl \"read/search all op attr\";" +
          "allow (search, read) " +
          "userattr!=\"l#New York\";)";
  private static final
  String notAllOpAttrAci1 = "(targetattr!=\"+\")" +
          "(version 3.0;acl \"read/search not all op attr\";" +
          "allow (search, read) " +
          "userattr!=\"l#New York\";)";
  private static final
  String userAttrAci = "(targetattr=\"*\")" +
          "(version 3.0;acl \"read/search userattr\";" +
          "(version 3.0;acl \"read/search all userattr\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
@@ -164,6 +201,129 @@
    deleteAttrFromEntry(user1, "aci");
  }
  /**
   * Test targetattr shorthand behavior, all attrs both user and operational.
   * See comments.
   *
   * @throws Exception  If a test result is unexpected.
   */
  @Test()
  public void testTargetAttrAllAttr() throws Exception {
    //Add aci with: (targetattr = "+ || *")
    String aciLdif=makeAddAciLdif("aci", user1, allAttrs);
    modEntries(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, opAttrList);
    Assert.assertFalse(userResults.equals(""));
    HashMap<String, String> attrMap=getAttrMap(userResults);
    //All should be returned.
    Assert.assertTrue(attrMap.containsKey("aci"));
    Assert.assertTrue(attrMap.containsKey("sn"));
    Assert.assertTrue(attrMap.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
  }
  /**
   * Test targetattr shorthand behavior, userattr and plus sign (all op attrs).
   * See comments.
   *
   * @throws Exception If a test result is unexpected.
   */
  @Test()
  public void testTargetAttrOpPlusAttr() throws Exception {
    //Add aci with: (targetattr = "objectclass|| +")
    String aciLdif=makeAddAciLdif("aci", user1, ocOpAttrs);
    modEntries(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, opAttrList);
    Assert.assertFalse(userResults.equals(""));
    HashMap<String, String> attrMap=getAttrMap(userResults);
    //Only aci should be returned.
    Assert.assertTrue(attrMap.containsKey("aci"));
    Assert.assertFalse(attrMap.containsKey("sn"));
    Assert.assertFalse(attrMap.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
  }
  /**
   * Test targetattr shorthand behavior, star (all user attr) or aci attr.
   * See comments.
   *
   * @throws Exception  If a test result is unexpected.
   */
  @Test()
  public void testTargetAttrUserStarAttr() throws Exception {
    //Add aci with: (targetattr = "*|| aci")
    String aciLdif=makeAddAciLdif("aci", user1, starAciAttrs);
    modEntries(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, opAttrList);
    Assert.assertFalse(userResults.equals(""));
    HashMap<String, String> attrMap=getAttrMap(userResults);
    //All should be returned.
    Assert.assertTrue(attrMap.containsKey("aci"));
    Assert.assertTrue(attrMap.containsKey("sn"));
    Assert.assertTrue(attrMap.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
  }
  /**
   * Test targetattr shorthand behavior using '+' in expression and an
   * operational attribute in the filter. The second test is two ACIs one
   * with targetattr='+' and the other with targetattr='*'.
   *
   * @throws Exception If test result is unexpected.
   */
  @Test()
  public void testTargetAttrSrchShorthand() throws Exception {
    //Aci: (targetattrs="sn || uid || +) and search with an
    //operational attr (aci).
    String aciLdif=makeAddAciLdif("aci", user1, OpSrchAttrs);
    modEntries(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, aciFilter, opAttrList);
    Assert.assertFalse(userResults.equals(""));
    HashMap<String, String> attrMap=getAttrMap(userResults);
    //All should be returned.
    Assert.assertTrue(attrMap.containsKey("aci"));
    Assert.assertTrue(attrMap.containsKey("sn"));
    Assert.assertTrue(attrMap.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
    //Add two ACIs, one with '+' and the other with '*'.
    String aciLdif1=makeAddAciLdif("aci", user1, allOpAttrAci1, userAttrAci);
    modEntries(aciLdif1, DIR_MGR_DN, PWD);
    String userResults1 =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, aciFilter, opAttrList);
    Assert.assertFalse(userResults1.equals(""));
    HashMap<String, String> attrMap1=getAttrMap(userResults1);
    //All should be returned.
    Assert.assertTrue(attrMap1.containsKey("aci"));
    Assert.assertTrue(attrMap1.containsKey("sn"));
    Assert.assertTrue(attrMap1.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
        //Add two ACIs, one with '+' and the other with '*'.
    String aciLdif2=makeAddAciLdif("aci", user1, notAllOpAttrAci1, userAttrAci);
    modEntries(aciLdif2, DIR_MGR_DN, PWD);
    String userResults2 =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, opAttrList);
    Assert.assertFalse(userResults2.equals(""));
    HashMap<String, String> attrMap2=getAttrMap(userResults2);
    //Only non-operation should be returned.
    Assert.assertFalse(attrMap2.containsKey("aci"));
    Assert.assertTrue(attrMap2.containsKey("sn"));
    Assert.assertTrue(attrMap2.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
  }
  private void
  checkAttributeVal(HashMap<String, String> attrMap, String attr,
                      String val) throws Exception {