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

dugan
17.33.2007 9abc65098b6b8267dc67847433a5b041a3217096
opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -250,6 +250,27 @@
    public static final int TARGATTRFILTERS_DELETE = 0x2000;
    /**
     * ACI_ATTR_STAR_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 attributes expression (targetattr="*") target match.
     * For this flag to be set, there must be only one ACI matching.
     *
     * This flag and ACI_FOUND_ATTR_RULE are used in the
     * AciHandler.filterEntry.accessAllowedAttrs method to skip access
     * 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;
    /**
     * ACI_FOUND_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.
     */
    public static final int ACI_FOUND_ATTR_RULE = 0x0010;
    /**
     * ACI_NULL is used to set the container rights to all zeros. Used
     * by LDAP modify.
     */
opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -101,6 +101,12 @@
     * The entry being evaluated (resource entry).
     */
    private Entry resourceEntry;
    /*
     * Saves the resource entry. Used in geteffectiverights evaluation to
     * restore the current resource entry state after a read right was
     * evaluated.
     */
    private Entry saveResourceEntry;
    /*
@@ -225,6 +231,11 @@
     */
    private String summaryString=null;
   /*
    * Flag used to determine if ACI all attributes target matched.
    */
    private int evalAllAttributes=0;
  /**
     * This constructor is used by all currently supported LDAP operations.
     *
@@ -265,6 +276,9 @@
          this.specificAttrs=getEffectiveRightsControl.getAttributes();
          fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
        }
        String allAttrs=(String)operation.getAttachment(ALL_ATTRS_MATCHED);
        if(allAttrs != null)
          evalAllAttributes = ACI_ATTR_STAR_MATCHED;
      }
      //Reference the current authorization entry, so it can be put back
      //if an access proxy check was performed.
@@ -791,4 +805,33 @@
        return "selfwrite";
      return null;
  }
  /**
   * {@inheritDoc}
   */
  public  void setACIEvalAttributesRule(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;
      } else
        evalAllAttributes |= Aci.ACI_ATTR_STAR_MATCHED;
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean hasACIEvalAttributes() {
    return (evalAllAttributes == 0) ||
           (evalAllAttributes & ACI_FOUND_ATTR_RULE) == ACI_FOUND_ATTR_RULE;
  }
  /**
   * {@inheritDoc}
   */
  public void clearACIEvalAttributesRule(int v) {
    evalAllAttributes &= ~v;
  }
}
opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -85,6 +85,13 @@
    public static String ALL_ATTRS_RESOURCE_ENTRY = "allAttrsResourceEntry";
    /**
     * String used to indicate that the evaluating ACI had a all attributes
     * targetattr match (targetattr="*").
     */
     public static String ALL_ATTRS_MATCHED = "allAttrsMatched";
    /**
     * This constructor instantiates the ACI handler class that performs the
     * main processing for the dseecompat ACI package. It does the following
     * initializations:
@@ -556,16 +563,16 @@
        return ret;
    }
  /**
   * Check if the specified attribute type is a DN by checking if its syntax
   * OID is equal to the DN syntax OID.
   * @param attribute The attribute type to check.
   * @return True if the attribute type syntax OID is equal to a DN syntax OID.
   */
  private boolean isAttributeDN(AttributeType attribute) {
    return (attribute.getSyntaxOID().equals(SYNTAX_DN_OID));
  }
    /**
     * Check if the specified attribute type is a DN by checking if its syntax
     * OID is equal to the DN syntax OID.
     * @param attribute The attribute type to check.
     * @return True if the attribute type syntax OID is equal to a DN syntax
     *         OID.
     */
    private boolean isAttributeDN(AttributeType attribute) {
      return (attribute.getSyntaxOID().equals(SYNTAX_DN_OID));
    }
    /**
     * Performs an access check against all of the attributes of an entry.
@@ -579,15 +586,17 @@
     */
    private SearchResultEntry
    accessAllowedAttrs(AciLDAPOperationContainer container) {
        Entry e=container.getResourceEntry();
        List<AttributeType> typeList=getAllAttrs(e);
        for(AttributeType attrType : typeList) {
            container.setCurrentAttributeType(attrType);
            if(!accessAllowed(container)) {
                e.removeAttribute(attrType);
            }
      Entry e=container.getResourceEntry();
      List<AttributeType> typeList=getAllAttrs(e);
      for(AttributeType attrType : typeList) {
        if(!container.hasACIEvalAttributes() && !attrType.isOperational())
          continue;
        container.setCurrentAttributeType(attrType);
        if(!accessAllowed(container)) {
          e.removeAttribute(attrType);
        }
        return container.getSearchResultEntry();
      }
      return container.getSearchResultEntry();
    }
    /**
@@ -600,6 +609,8 @@
     */
    private List<AttributeType> getAllAttrs(Entry e) {
        Map<AttributeType,List<Attribute>> attrMap = e.getUserAttributes();
        Map<AttributeType,List<Attribute>> opAttrMap =
                                                   e.getOperationalAttributes();
        List<AttributeType> typeList=new LinkedList<AttributeType>();
        Attribute attr=e.getObjectClassAttribute();
        /*
@@ -611,6 +622,7 @@
           typeList.add(ocType);
        }
        typeList.addAll(attrMap.keySet());
        typeList.addAll(opAttrMap.keySet());
        return typeList;
    }
@@ -877,6 +889,8 @@
          if (ret) {
              operationContainer.setRights(ACI_READ);
              ret=accessAllowedEntry(operationContainer);
              if(ret && !operationContainer.hasACIEvalAttributes())
                operation.setAttachment(ALL_ATTRS_MATCHED, ALL_ATTRS_MATCHED);
          }
      }
      if(ret && operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS) != null)
opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -165,6 +165,39 @@
     * @return  True if a match context is evaluating geteffectiverights.
     */
    boolean isGetEffectiveRightsEval();
  /**
   * 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="*").
   *
   * The only case where individual non-operational attribute access checking
   * can be skipped, is when a single ACI matched using a targetattr
   * all attributes rule.
   *
   * @param v  The flag to set the mask to.
   */
  void setACIEvalAttributesRule(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
   * matched.
   *
   * @return  True if the above condition was seen.
   */
    boolean hasACIEvalAttributes();
  /**
   * Used to clear the mask used to detect if access checking needs to be
   * performed on individual non-operational attributes types.
   *
   * @param v  The flag to clear (always ACI_ATTR_STAR_MATCHED)
   */
    public void clearACIEvalAttributesRule(int v);
}
opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -411,9 +411,23 @@
            AttributeType a=targetMatchCtx.getCurrentAttributeType();
            int rights=targetMatchCtx.getRights();
            boolean isFirstAttr=targetMatchCtx.isFirstAttribute();
            if((a != null) && (targets.getTargetAttr() != null))
                ret=TargetAttr.isApplicable(a, targets.getTargetAttr());
            else if((a != null) || (targets.getTargetAttr() != null)) {
            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);
            } else if((a != null) || (targets.getTargetAttr() != null)) {
                if((aci.hasRights(skipRights)) &&
                                                (skipRightsHasRights(rights)))
                    ret=true;
opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -178,7 +178,6 @@
     */
    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
        EnumEvalResult matched;
        boolean undefined=false;
        switch(userAttrType) {
        case ROLEDN:
@@ -194,9 +193,7 @@
        default:
            matched=evalVAL(evalCtx);
        }
        if(matched == EnumEvalResult.ERR)
            undefined=true;
        return matched.getRet(type, undefined);
        return matched;
    }
    /** Evaluate a VALUE userattr type. Look in client entry for an
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
New file
@@ -0,0 +1,300 @@
/*
 * 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.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPSearch;
import static org.opends.server.util.ServerConstants.EOL;
import org.testng.annotations.Test;
import org.testng.Assert;
import java.io.*;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
@Test(groups = { "precommit", "dseecompat" })
public abstract class  AciTestCase extends DirectoryServerTestCase {
  public static final String DIR_MGR_DN = "cn=Directory Manager";
  public static final String PWD = "password";
  public  static final String filter = "(objectclass=*)";
  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 =
           new ThreadLocal<Map<String,File>>();
  protected String LDAPSearchCtrl(String bindDn, String bindPassword,
                            String proxyDN, String controlStr,
                            String base, String filter, String attr)
          throws Exception {
    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("-T");
    if(proxyDN != null) {
      argList.add("-Y");
      argList.add("dn:" + proxyDN);
    }
    if(controlStr != null) {
      argList.add("-J");
      argList.add(controlStr);
    }
    argList.add("-b");
    argList.add(base);
    argList.add("-s");
    argList.add("sub");
    argList.add(filter);
    String[] attrs=attr.split("\\s+");
    for(String a : attrs)
     argList.add(a);
    String[] args = new String[argList.size()];
    oStream.reset();
    int retVal =
            LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
    Assert.assertEquals(0, retVal,  "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  protected String LDAPSearchParams(String bindDn, String bindPassword,
                            String proxyDN, String authzid, String[] attrList,
                            String base, String filter ,String attr)
          throws Exception {
    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("-T");
    if(proxyDN != null) {
      argList.add("-Y");
      argList.add("dn:" + proxyDN);
    }
    if(authzid != null) {
      argList.add("-g");
      argList.add(authzid);
    }
    if(attrList != null) {
      for(String a : attrList) {
        argList.add("-e");
        argList.add(a);
      }
    }
    argList.add("-b");
    argList.add(base);
    argList.add("-s");
    argList.add("sub");
    argList.add(filter);
    String[] attrs=attr.split("\\s+");
    for(String a : attrs)
     argList.add(a);
    String[] args = new String[argList.size()];
    oStream.reset();
    int retVal =
         LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  protected void modEntries(String ldif, String bindDn, String bindPassword)
          throws Exception {
    File tempFile = getTemporaryLdifFile();
    TestCaseUtils.writeFile(tempFile, ldif);
    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("-f");
    argList.add(tempFile.getAbsolutePath());
    String[] args = new String[argList.size()];
    ldapModify(argList.toArray(args));
  }
  protected void ldapModify(String[] args) {
    oStream.reset();
    LDAPModify.mainModify(args, false, oStream, oStream);
  }
  protected void deleteAttrFromEntry(String dn, String attr)
  throws Exception {
    StringBuilder ldif = new StringBuilder();
    ldif.append(TestCaseUtils.makeLdif(
            "dn: "  + dn,
            "changetype: modify",
            "delete: " + attr));
    modEntries(ldif.toString(), DIR_MGR_DN, PWD);
  }
  protected static String makeAddAciLdif(String attr, String dn, String... acis) {
    StringBuilder ldif = new StringBuilder();
    ldif.append("dn: ").append(dn).append(EOL);
    ldif.append("changetype: modify").append(EOL);
    ldif.append("add: ").append(attr).append(EOL);
    for(String aci : acis)
      ldif.append(attr).append(":").append(aci).append(EOL);
    ldif.append(EOL);
    return ldif.toString();
  }
  protected File getTemporaryLdifFile() throws IOException {
    Map<String,File> tempFilesForThisThread = tempLdifFile.get();
    if (tempFilesForThisThread == null) {
      tempFilesForThisThread = new HashMap<String,File>();
      tempLdifFile.set(tempFilesForThisThread);
    }
    File tempFile = tempFilesForThisThread.get("effectiverights-tests");
    if (tempFile == null) {
      tempFile = File.createTempFile("effectiverights-tests", ".ldif");
      tempFile.deleteOnExit();
      tempFilesForThisThread.put("effectiverights-tests", tempFile);
    }
    return tempFile;
  }
  protected void addEntries() throws Exception {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntries(
            "dn: ou=People,o=test",
            "objectClass: top",
            "objectClass: organizationalUnit",
            "ou: People",
            "",
            "dn: ou=admins,o=test",
            "objectClass: top",
            "objectClass: organizationalUnit",
            "ou: admins",
            "",
            "dn: cn=group,ou=People,o=test",
            "objectclass: top",
            "objectclass: groupOfNames",
            "cn: group",
            "member: uid=user.1,ou=People,o=test",
            "",
            "dn: uid=superuser,ou=admins,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: superuser",
            "givenName: superuser",
            "sn: 1",
            "cn: User 1",
            "userPassword: password",
            "ds-privilege-name: proxied-auth",
            "",
            "dn: uid=proxyuser,ou=admins,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: proxyuser",
            "givenName: proxyuser",
            "sn: 1",
            "cn: User 1",
            "userPassword: password",
            "",
            "dn: uid=user.1,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.1",
            "givenName: User 1",
            "sn: 1",
            "cn: User1",
            "l: Austin",
            "userPassword: password",
            "",
            "dn: uid=user.2,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.2",
            "givenName: User 2",
            "sn: 2",
            "cn: User 2",
             "l: dallas",
            "userPassword: password",
            "",
            "dn: uid=user.3,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.3",
            "givenName: User 3",
            "sn: 3",
            "mail: user.3@test",
            "description: user.3 description",
            "cn: User 3",
            "l: Austin",
            "userPassword: password");
  }
  protected HashMap<String, String>
  getAttrMap(String resultString) throws Exception {
    StringReader r=new StringReader(resultString);
    BufferedReader br=new BufferedReader(r);
    HashMap<String, String> attrMap = new HashMap<String,String>();
    try {
      while(true) {
        String s = br.readLine();
        if(s == null)
          break;
        if(s.startsWith("dn:"))
          continue;
        String[] a=s.split(": ");
        if(a.length != 2)
          break;
        attrMap.put(a[0],a[1]);
      }
    } catch (IOException e) {
      Assert.assertEquals(0, 1,  e.getMessage());
    }
    return attrMap;
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
@@ -32,26 +32,11 @@
import org.testng.annotations.BeforeMethod;
import static org.opends.server.config.ConfigConstants.*;
import org.testng.Assert;
import static org.testng.Assert.assertEquals;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attribute;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.tools.LDAPModify;
import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
import static org.opends.server.util.ServerConstants.EOL;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
public class GetEffectiveRightsTestCase {
  private static ByteArrayOutputStream oStream = new ByteArrayOutputStream();
  private static final String DIR_MGR_DN = "cn=Directory Manager";
  private static final String PWD = "password";
  private static final String filter = "(objectclass=*)";
public class GetEffectiveRightsTestCase extends AciTestCase {
  private static final String base="uid=user.3,ou=People,o=test";
  private static final String user1="uid=user.1,ou=People,o=test";
  private static final String superUser="uid=superuser,ou=admins,o=test";
@@ -79,9 +64,6 @@
  private static final
  String allRights = "add:1,delete:1,read:1,write:1,proxy:1";
  private static final
  String ACCESS_HANDLER_DN = "cn=Access Control Handler,cn=config";
  //Results for attributeLevel searches
  private static final String srwMailAttrRights =
          "search:1,read:1,compare:0,write:1," +
@@ -415,253 +397,4 @@
    String retRightsStr=attrMap.get(entryLevel);
    Assert.assertTrue(retRightsStr.equals(reqRightsStr));
 }
 private HashMap<String, String>
 getAttrMap(String resultString) throws Exception {
       StringReader r=new StringReader(resultString);
    BufferedReader br=new BufferedReader(r);
    HashMap<String, String> attrMap = new HashMap<String,String>();
    try {
      while(true) {
        String s = br.readLine();
        if(s == null)
          break;
        if(s.startsWith("dn:"))
          continue;
        String[] a=s.split(": ");
        if(a.length != 2)
          break;
        attrMap.put(a[0],a[1]);
      }
    } catch (IOException e) {
      Assert.assertEquals(0, 1,  e.getMessage());
    }
   return attrMap;
 }
  private void addEntries() throws Exception {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntries(
            "dn: ou=People,o=test",
            "objectClass: top",
            "objectClass: organizationalUnit",
            "ou: People",
            "",
            "dn: ou=admins,o=test",
            "objectClass: top",
            "objectClass: organizationalUnit",
            "ou: admins",
            "",
            "dn: cn=group,ou=People,o=test",
            "objectclass: top",
            "objectclass: groupOfNames",
            "cn: group",
            "member: uid=user.1,ou=People,o=test",
            "",
            "dn: uid=superuser,ou=admins,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: superuser",
            "givenName: superuser",
            "sn: 1",
            "cn: User 1",
            "userPassword: password",
            "ds-privilege-name: proxied-auth",
            "",
            "dn: uid=proxyuser,ou=admins,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: proxyuser",
            "givenName: proxyuser",
            "sn: 1",
            "cn: User 1",
            "userPassword: password",
            "",
            "dn: uid=user.1,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.1",
            "givenName: User",
            "sn: 1",
            "cn: User 1",
            "userPassword: password",
            "",
            "dn: uid=user.2,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.2",
            "givenName: User",
            "sn: 2",
            "cn: User 2",
            "userPassword: password",
            "",
            "dn: uid=user.3,ou=People,o=test",
            "objectClass: top",
            "objectClass: person",
            "objectClass: organizationalPerson",
            "objectClass: inetOrgPerson",
            "uid: user.3",
            "givenName: User",
            "sn: 3",
            "mail: user.3@test",
            "description: user.3 description",
            "cn: User 3",
            "userPassword: password");
  }
  private String LDAPSearchCtrl(String bindDn, String bindPassword,
                            String proxyDN, String controlStr,
                            String base, String filter, String attr)
          throws Exception {
    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("-T");
    if(proxyDN != null) {
      argList.add("-Y");
      argList.add("dn:" + proxyDN);
    }
    if(controlStr != null) {
      argList.add("-J");
      argList.add(controlStr);
    }
    argList.add("-b");
    argList.add(base);
    argList.add("-s");
    argList.add("sub");
    argList.add(filter);
    String[] attrs=attr.split("\\s+");
    for(String a : attrs)
     argList.add(a);
    String[] args = new String[argList.size()];
    oStream.reset();
    int retVal =
            LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
    Assert.assertEquals(0, retVal,  "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  private String LDAPSearchParams(String bindDn, String bindPassword,
                            String proxyDN, String authzid, String[] attrList,
                            String base, String filter ,String attr)
          throws Exception {
    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("-T");
    if(proxyDN != null) {
      argList.add("-Y");
      argList.add("dn:" + proxyDN);
    }
    if(authzid != null) {
      argList.add("-g");
      argList.add(authzid);
    }
    if(attrList != null) {
      for(String a : attrList) {
        argList.add("-e");
        argList.add(a);
      }
    }
    argList.add("-b");
    argList.add(base);
    argList.add("-s");
    argList.add("sub");
    argList.add(filter);
    String[] attrs=attr.split("\\s+");
    for(String a : attrs)
     argList.add(a);
    String[] args = new String[argList.size()];
    oStream.reset();
    int retVal =
         LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
    return oStream.toString();
  }
  private void modEntries(String ldif, String bindDn, String bindPassword)
          throws Exception {
    File tempFile = getTemporaryLdifFile();
    TestCaseUtils.writeFile(tempFile, ldif);
    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("-f");
    argList.add(tempFile.getAbsolutePath());
    String[] args = new String[argList.size()];
    ldapModify(argList.toArray(args));
  }
  private void ldapModify(String[] args) {
    oStream.reset();
    LDAPModify.mainModify(args, false, oStream, oStream);
  }
  private void deleteAttrFromEntry(String dn, String attr)
  throws Exception {
    StringBuilder ldif = new StringBuilder();
    ldif.append(TestCaseUtils.makeLdif(
            "dn: "  + dn,
            "changetype: modify",
            "delete: " + attr));
    modEntries(ldif.toString(), DIR_MGR_DN, PWD);
  }
  private static ThreadLocal<Map<String,File>> tempLdifFile =
          new ThreadLocal<Map<String,File>>();
  private File getTemporaryLdifFile() throws IOException {
    Map<String,File> tempFilesForThisThread = tempLdifFile.get();
    if (tempFilesForThisThread == null) {
      tempFilesForThisThread = new HashMap<String,File>();
      tempLdifFile.set(tempFilesForThisThread);
    }
    File tempFile = tempFilesForThisThread.get("effectiverights-tests");
    if (tempFile == null) {
      tempFile = File.createTempFile("effectiverights-tests", ".ldif");
      tempFile.deleteOnExit();
      tempFilesForThisThread.put("effectiverights-tests", tempFile);
    }
    return tempFile;
  }
  private static String makeAddAciLdif(String attr, String dn, String... acis) {
    StringBuilder ldif = new StringBuilder();
    ldif.append("dn: ").append(dn).append(EOL);
    ldif.append("changetype: modify").append(EOL);
    ldif.append("add: ").append(attr).append(EOL);
    for(String aci : acis)
      ldif.append(attr).append(":").append(aci).append(EOL);
    ldif.append(EOL);
    return ldif.toString();
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
New file
@@ -0,0 +1,166 @@
/*
 * 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.BeforeClass;
import org.testng.annotations.Test;
import org.testng.Assert;
import org.opends.server.TestCaseUtils;
import static org.opends.server.config.ConfigConstants.*;
import java.util.HashMap;
public class TargetAttrTestCase extends AciTestCase {
  private static String attrList="sn uid l";
  private static String opAttrList="sn uid aci";
  private static final String user1="uid=user.1,ou=People,o=test";
  private static final String user3="uid=user.3,ou=People,o=test";
  public  static final String aciFilter = "(aci=*)";
  private static final
  String userAttrAci = "(targetattr=\"*\")" +
          "(version 3.0;acl \"read/search userattr\";" +
          "allow (search, read) " +
          "userattr=\"l#Austin\";)";
  private static final
  String userAttrAci1 = "(targetattr=\"*\")" +
          "(version 3.0;acl \"read/search userattr\";" +
          "allow (search, read) " +
          "userattr!=\"l#New York\";)";
  private static final
  String nonOpAttrAci = "(targetattr=\"*\")" +
          "(version 3.0;acl \"read/search non-operational attr\";" +
          "allow (search, read) " +
          "userdn=\"ldap:///uid=user.3,ou=People,o=test\";)";
  private static final
  String opAttrAci = "(targetattr=\"aci\")" +
          "(version 3.0;acl \"read/search operational attr\";" +
          "allow (search, read) " +
          "userdn=\"ldap:///uid=user.3,ou=People,o=test\";)";
  @BeforeClass
  public void setupClass() throws Exception {
    TestCaseUtils.startServer();
    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
    addEntries();
  }
  /**
   * Test targetattr behavior using userattr bind rule.
   *
   * @throws Exception  If a test result is unexpected.
   */
  @Test()
  public void testTargetAttrUserAttr() throws Exception {
    String aciLdif=makeAddAciLdif("aci", user1, userAttrAci);
    modEntries(aciLdif, DIR_MGR_DN, PWD);
    String userResults =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, attrList);
    Assert.assertFalse(userResults.equals(""));
    HashMap<String, String> attrMap=getAttrMap(userResults);
    checkAttributeVal(attrMap, "l", "Austin");
    checkAttributeVal(attrMap, "sn", "1");
    checkAttributeVal(attrMap, "uid", "user.1");
    deleteAttrFromEntry(user1, "aci");
    String aciLdif1=makeAddAciLdif("aci", user1, userAttrAci1);
    modEntries(aciLdif1, DIR_MGR_DN, PWD);
    String userResults1 =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, attrList);
    Assert.assertFalse(userResults1.equals(""));
    HashMap<String, String> attrMap1=getAttrMap(userResults1);
    checkAttributeVal(attrMap1, "l", "Austin");
    checkAttributeVal(attrMap1, "sn", "1");
    checkAttributeVal(attrMap1, "uid", "user.1");
    deleteAttrFromEntry(user1, "aci");
  }
  /**
   * Test targetattr and operational attribute behavior. See comments.
   *
   * @throws Exception If a test result is unexpected.
   */
  @Test()
  public void testTargetAttrOpAttr() throws Exception {
    //Add aci that only allows non-operational attributes search/read.
    String aciLdif=makeAddAciLdif("aci", user1, nonOpAttrAci);
    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);
    //The aci attribute type is operational, it should not be there.
    //The other two should be there.
    Assert.assertFalse(attrMap.containsKey("aci"));
    Assert.assertTrue(attrMap.containsKey("sn"));
    Assert.assertTrue(attrMap.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
    //Add aci that allows both non-operational attributes and the operational
    //attribute "aci" search/read.
    String aciLdif1=makeAddAciLdif("aci", user1, nonOpAttrAci, opAttrAci);
    modEntries(aciLdif1, DIR_MGR_DN, PWD);
    String userResults1 =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, filter, opAttrList);
    Assert.assertFalse(userResults1.equals(""));
    HashMap<String, String> attrMap1=getAttrMap(userResults1);
    //All three attributes should be there.
    Assert.assertTrue(attrMap1.containsKey("aci"));
    Assert.assertTrue(attrMap1.containsKey("sn"));
    Assert.assertTrue(attrMap1.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
    //Add ACI that only allows only aci operational attribute search/read.
    String aciLdif2=makeAddAciLdif("aci", user1, opAttrAci);
    modEntries(aciLdif2, DIR_MGR_DN, PWD);
    String userResults2 =
            LDAPSearchParams(user3, PWD, null, null, null,
                    user1, aciFilter, opAttrList);
    Assert.assertFalse(userResults2.equals(""));
    HashMap<String, String> attrMap2=getAttrMap(userResults2);
    //Only operational attribute aci should be there, the other two should
    //not.
    Assert.assertTrue(attrMap2.containsKey("aci"));
    Assert.assertFalse(attrMap2.containsKey("sn"));
    Assert.assertFalse(attrMap2.containsKey("uid"));
    deleteAttrFromEntry(user1, "aci");
  }
  private void
  checkAttributeVal(HashMap<String, String> attrMap, String attr,
                      String val) throws Exception {
    String mapVal=attrMap.get(attr);
    Assert.assertTrue(mapVal.equals(val));
  }
}