From fe19ac2d6f1b978356b29e81901b91ae7a09daf9 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Fri, 02 Oct 2015 12:39:01 +0000
Subject: [PATCH] OPENDJ-2312 Check rightsMask for all operations in setEval{User,Op}Attributes

---
 opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java |   84 ++++++++++++++++++++++++++++
 opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/AciTestCase.java        |   73 +++++++++++++++++++++--
 opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java       |    4 
 3 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
index 69a2ee9..4477aeb 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -805,7 +805,7 @@
   /** {@inheritDoc} */
   @Override
   public  void setEvalUserAttributes(int v) {
-    if(operation instanceof SearchOperation && rightsMask == ACI_READ) {
+    if(rightsMask == ACI_READ) {
       if(v == ACI_FOUND_USER_ATTR_RULE) {
         evalAllAttributes |= ACI_FOUND_USER_ATTR_RULE;
         evalAllAttributes &= ~ACI_USER_ATTR_STAR_MATCHED;
@@ -820,7 +820,7 @@
   /** {@inheritDoc} */
   @Override
   public  void setEvalOpAttributes(int v) {
-    if(operation instanceof SearchOperation && rightsMask == ACI_READ) {
+    if(rightsMask == ACI_READ) {
       if(v == ACI_FOUND_OP_ATTR_RULE) {
         evalAllAttributes |= ACI_FOUND_OP_ATTR_RULE;
         evalAllAttributes &= ~ACI_OP_ATTR_PLUS_MATCHED;
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/AciTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/AciTestCase.java
index a7adc51..675d984 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/AciTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -199,6 +199,47 @@
     return oStream.toString();
   }
 
+  /**
+   * Perform a modify operation, and request attributes via a preRead control.
+   *
+   * @param bindDn        The user to authenticate as.
+   * @param bindPassword  The user's credentials.
+   * @param ldif          The modification to make.
+   * @param attributes    A space-separated list of attributes to return.
+   *
+   * @return  The output of the command.
+   *
+   * @throws Exception  If an unexpected problem occurred.
+   */
+  protected String preReadModify(String bindDn, String bindPassword,
+                                 String ldif, String attributes) throws Exception
+  {
+    File tempFile = getTemporaryLdifFile();
+    TestCaseUtils.writeFile(tempFile, ldif);
+
+    ArrayList<String> argList=new ArrayList<>(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 (attributes != null) {
+      argList.add("--preReadAttributes");
+      argList.add(attributes);
+    }
+    argList.add("-f");
+    argList.add(tempFile.getAbsolutePath());
+    String[] args = new String[argList.size()];
+
+    oStream.reset();
+    int retVal =LDAPModify.mainModify(argList.toArray(args), false, oStream, oStream);
+    Assert.assertEquals(retVal, 0, "Returned error: " + oStream);
+    return oStream.toString();
+  }
+
   protected String LDAPSearchCtrl(String bindDn, String bindPassword,
                             String proxyDN, String controlStr,
                             String base, String filter, String attr) {
@@ -719,26 +760,42 @@
 
   protected Map<String, String> getAttrMap(String resultString)
   {
-    StringReader r=new StringReader(resultString);
-    BufferedReader br=new BufferedReader(r);
+    return getAttrMap(resultString, false);
+  }
+
+  /**
+   * Parse a tool output for an LDIF record, returning the attributes in a Map.
+   *
+   * @param resultString The entire output from the operation
+   * @param stripHeader  Set to {@code true} if data before the LDIF needs to be ignored
+   * @return  A map of attribute-values
+   */
+  protected Map<String, String> getAttrMap(String resultString, boolean stripHeader)
+  {
+    StringReader r = new StringReader(resultString);
+    BufferedReader br = new BufferedReader(r);
+    boolean stripping = stripHeader;
     Map<String, String> attrMap = new HashMap<>();
     try {
-      while(true) {
+      while (true) {
         String s = br.readLine();
-        if(s == null)
+        if (s == null)
         {
           break;
         }
-        if(s.startsWith("dn:"))
-        {
+        if (stripping) {
+          if (s.startsWith("dn:"))
+          {
+            stripping = false;
+          }
           continue;
         }
         String[] a=s.split(": ");
-        if(a.length != 2)
+        if (a.length != 2)
         {
           break;
         }
-        attrMap.put(a[0].toLowerCase(),a[1]);
+        attrMap.put(a[0].toLowerCase(), a[1]);
       }
     } catch (IOException e) {
       Assert.fail(e.getMessage());
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
index 27d6ddf..0be9464 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -122,9 +122,42 @@
           "allow (search, read) " +
           "userattr=\"l#Austin\";)";
 
+  private static final
+  String controlAci = "(targetcontrol=\"1.3.6.1.1.13.1\")" +
+          "(version 3.0;acl \"use pre-read control\";" +
+          "allow (read) " +
+          "userdn=\"ldap:///anyone\";)";
+
+  private static final String user3ForbiddenUserAttr = "sn";
+  private static final String user3ForbiddenOperationalAttr = "createTimestamp";
+  private static final String user3AllowedUserAttr = "uid";
+  private static final String user3AllowedOperationalAttr = "ds-privilege-name";
+  private static final String user3WritableAttr = "description";
+
+    private static final
+  String selfWriteAci = "(targetattr=\"" + user3WritableAttr + "\")" +
+          "(version 3.0;acl \"self write description\";" +
+          "allow (write) " +
+          "userdn=\"ldap:///self\";)";
+
+  private static final
+  String selfDenyAttrReadAci = "(targetattr=\"" + user3ForbiddenUserAttr + "||" +
+          user3ForbiddenOperationalAttr + "\")" +
+          "(version 3.0;acl \"self deny attribute reads\";" +
+          "deny (read,search) " +
+          "userdn=\"ldap:///self\";)";
+
+  private static final
+  String selfReadAllAttrsAci = "(targetattr=\"*||+\")" +
+          "(version 3.0; acl \"self read/search all attributes\";" +
+          "allow (read,search) " +
+          "userdn=\"ldap:///self\";)";
+
   @BeforeClass
   public void setupClass() throws Exception {
     deleteAttrFromAdminEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+    String aciLdif3 = makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN, controlAci, selfWriteAci);
+    LDIFModify(aciLdif3, DIR_MGR_DN, PWD);
     addEntries("o=test");
   }
 
@@ -217,6 +250,57 @@
   }
 
   /**
+   * Test targetattr behaviour with modify and pre-read controls
+   *
+   * @throws Exception  If a test result is unexpected.
+   */
+  @Test
+  public void testTargetAttrPreRead() throws Exception {
+    String aciLdif=makeAddLDIF("aci", user3,
+            controlAci, selfWriteAci, selfDenyAttrReadAci, selfReadAllAttrsAci);
+    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+
+    // sanity check that search does not return the forbidden attributes
+    String searchResults =
+            LDAPSearchParams(user3, PWD, null, null, null, user3, filter, "+ *");
+    assertNotEquals(searchResults, "");
+    Map<String, String> attrMap = getAttrMap(searchResults);
+    assertFalse(attrMap.containsKey(user3ForbiddenUserAttr));
+    assertFalse(attrMap.containsKey(user3ForbiddenOperationalAttr));
+    assertTrue(attrMap.containsKey(user3AllowedUserAttr));
+
+    // check we can't pre-read the forbidden user attribute
+    String modifyLdif1 = makeAddLDIF(user3WritableAttr, user3, "don't care 1");
+    String modifyResults1 = preReadModify(user3, PWD, modifyLdif1, user3ForbiddenUserAttr);
+    assertNotEquals(modifyResults1, "");
+    Map<String, String> modifyMap1 = getAttrMap(modifyResults1, true);
+    assertFalse(modifyMap1.containsKey(user3ForbiddenUserAttr));
+
+    // check we can't pre-read the forbidden operational attribute
+    String modifyLdif2 = makeAddLDIF(user3WritableAttr, user3, "don't care 2");
+    String modifyResults2 = preReadModify(user3, PWD, modifyLdif2, user3ForbiddenOperationalAttr);
+    assertNotEquals(modifyResults2, "");
+    Map<String, String> modifyMap2 = getAttrMap(modifyResults2, true);
+    assertFalse(modifyMap2.containsKey(user3ForbiddenOperationalAttr));
+
+    // check we can pre-read the allowed user attribute
+    String modifyLdif3 = makeAddLDIF(user3WritableAttr, user3, "don't care 3");
+    String modifyResults3 = preReadModify(user3, PWD, modifyLdif3, user3AllowedUserAttr);
+    assertNotEquals(modifyResults3, "");
+    Map<String, String> modifyMap3 = getAttrMap(modifyResults3, true);
+    assertTrue(modifyMap3.containsKey(user3AllowedUserAttr));
+
+    // check we can pre-read the allowed operational attribute
+    String modifyLdif4 = makeAddLDIF(user3WritableAttr, user3, "don't care 4");
+    String modifyResults4 = preReadModify(user3, PWD, modifyLdif4, user3AllowedOperationalAttr);
+    assertNotEquals(modifyResults4, "");
+    Map<String, String> modifyMap4 = getAttrMap(modifyResults4, true);
+    assertTrue(modifyMap4.containsKey(user3AllowedOperationalAttr));
+
+    deleteAttrFromEntry(user3, "aci");
+  }
+
+  /**
    * Test targetattr shorthand behavior, all attrs both user and operational.
    * See comments.
    *

--
Gitblit v1.10.0