From 09b2bb485c8939161985e4542ec791b695e88ed9 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Fri, 15 Jun 2007 22:59:08 +0000
Subject: [PATCH] Fix userattr bind rule GROUPDN keyword when using a  url search failure . Issue 1596.

---
 opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java                          |   55 ++++++++++++++++--
 opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java        |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                                   |   17 ++++-
 opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java |   39 +++++++++++++
 opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java                                    |    8 ++
 opends/src/server/org/opends/server/messages/AciMessages.java                                                |   47 +++++++++++++++
 6 files changed, 156 insertions(+), 13 deletions(-)

diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
index 1107f83..7ffe140 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
@@ -143,16 +143,22 @@
      * @param evalCtx  The evaluation context to use in the evaluation.
      * @param attributeType The attribute type of the entry to use to get the
      * values for the groupd DNs.
+     * @param suffixDN The suffix that the groupDN must be under. If it's null,
+     *                 then the groupDN can be anywhere in the DIT.
      * @return Enumeration evaluation result.
      */
     public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx,
-                                           AttributeType attributeType) {
+                                           AttributeType attributeType,
+                                           DN suffixDN) {
         EnumEvalResult matched= EnumEvalResult.FALSE;
         List<Attribute> attrs = e.getAttribute(attributeType);
         LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues();
         for(AttributeValue v : vals) {
             try {
                 DN groupDN=DN.decode(v.getStringValue());
+                if(suffixDN != null &&
+                   !groupDN.isDescendantOf(suffixDN))
+                        continue;
                 Group group = groupManager.getGroupInstance(groupDN);
                 if((group != null) && (evalCtx.isMemberOf(group))) {
                     matched=EnumEvalResult.TRUE;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java b/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
index 612e677..3b8a76e 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
@@ -31,11 +31,15 @@
 import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.StringTokenizer;
+import java.util.LinkedHashSet;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
+import org.opends.server.types.LDAPURL;
+import org.opends.server.types.DirectoryException;
 
 /**
  * This class is used by USERDN and GROUPDN userattr types
@@ -75,6 +79,13 @@
      */
     private String attrTypeStr;
 
+    /*
+     * The base DN of a URL parsed from the rule. Used to make sure groupdn
+     * are under this suffix. Originally a way to search all nested groups
+     * under this suffix, so the behavior is slightly different.
+     */
+    private DN baseDN=null;
+
 
     /**
      * Construct a class from the inheritance pattern. The skipParsing boolean
@@ -181,12 +192,35 @@
                 }
             }
         } else {
-            if((this.attributeType =
-                DirectoryServer.getAttributeType(pattern)) == null)
-                this.attributeType =
-                    DirectoryServer.getDefaultAttributeType(pattern);
-            numLevels=1;
-            levels[0]=0;
+          attrTypeStr=pattern;
+          if(pattern.startsWith(NULL_LDAP_URL)) {
+            try {
+              LDAPURL url=LDAPURL.decode(pattern, true);
+              LinkedHashSet<String>attrs=url.getAttributes();
+              if(attrs.size() != 1) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_ATTR_URL;
+                String message = getMessage(msgID, pattern);
+                throw new AciException(msgID, pattern);
+              }
+              baseDN=url.getBaseDN();
+              if(baseDN.isNullDN()){
+                int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_BASEDN_URL;
+                String message = getMessage(msgID, pattern);
+                throw new AciException(msgID, message);
+              }
+              attrTypeStr=attrs.iterator().next();
+            } catch (DirectoryException ex) {
+              int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_URL;
+              String message = getMessage(msgID, ex.getErrorMessage());
+              throw new AciException(msgID, message);
+            }
+          }
+          if((this.attributeType =
+                  DirectoryServer.getAttributeType(attrTypeStr)) == null)
+            this.attributeType =
+                    DirectoryServer.getDefaultAttributeType(attrTypeStr);
+          numLevels=1;
+          levels[0]=0;
         }
     }
 
@@ -221,5 +255,14 @@
     public String getAttrTypeStr() {
         return attrTypeStr;
     }
+
+  /**
+   * Return the DN that groupdn must be under.
+   *
+   * @return DN that groupdn must be under.
+   */
+  public DN getBaseDN() {
+      return baseDN;
+    }
 }
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index e50670c..5a10f8b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -323,6 +323,12 @@
         int numLevels=parentInheritance.getNumLevels();
         int[] levels=parentInheritance.getLevels();
         AttributeType attrType=parentInheritance.getAttributeType();
+        DN baseDN=parentInheritance.getBaseDN();
+        if(baseDN != null) {
+            if (evalCtx.getResourceEntry().hasAttribute(attrType))
+                matched=GroupDN.evaluate(evalCtx.getResourceEntry(),
+                        evalCtx,attrType, baseDN);
+        } else {
         for(int i=0;((i < numLevels) && !stop); i++ ) {
             //The ROLEDN keyword will always enter this statement. The others
             //might. For the add operation, the resource itself (level 0)
@@ -332,9 +338,9 @@
                     undefined=true;
                 } else if (evalCtx.getResourceEntry().hasAttribute(attrType)) {
                     matched =
-                        evalEntryAttr(evalCtx.getResourceEntry(),
-                                evalCtx,attrType);
-                   if(matched.equals(EnumEvalResult.TRUE))
+                            evalEntryAttr(evalCtx.getResourceEntry(),
+                                    evalCtx,attrType);
+                    if(matched.equals(EnumEvalResult.TRUE))
                         stop=true;
                 }
             } else {
@@ -362,7 +368,8 @@
                 }
             }
         }
-        return matched.getRet(type, undefined);
+    }
+    return matched.getRet(type, undefined);
     }
 
     /**
@@ -405,7 +412,7 @@
                 break;
             }
             case GROUPDN: {
-                result=GroupDN.evaluate(e, evalCtx, attributeType);
+                result=GroupDN.evaluate(e, evalCtx, attributeType, null);
                 break;
             }
         }
diff --git a/opends/src/server/org/opends/server/messages/AciMessages.java b/opends/src/server/org/opends/server/messages/AciMessages.java
index 811b377..1b366b6 100644
--- a/opends/src/server/org/opends/server/messages/AciMessages.java
+++ b/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -778,6 +778,35 @@
 
 
     /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr LDAP URL failed
+     * to decode.  This takes one argument the message from the LDAP
+     * URL decode DirectoryException.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 78;
+
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr LDAP URL contained
+     * a null base DN.  This takes one argument the ldap URL from the bind rule
+     * expression.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_BASEDN_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 79;
+
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr LDAP URL attribute
+     * field either contained more than one attribute or the field was null.
+     * This takes one argument the ldap URL from the bind rule expression.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_ATTR_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 80;
+
+    /**
      * Associates a set of generic messages with the message IDs defined in
      * this class.
      */
@@ -1220,5 +1249,23 @@
                 "invalid ACIs rules were detected either when the server " +
                 "was started or during a backend initialization");
 
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression value failed to URL decode for " +
+                "the following reason: %s");
+
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_BASEDN_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression value failed to parse because the " +
+                "ldap URL \"%s\" contains an empty base DN");
+
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_ATTR_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression value failed to parse because the " +
+                "attribute field of the ldap URL \"%s\" either contains more " +
+                "than one description or the field is empty");
     }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
index 5d6d9c7..ed2b4be 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -211,7 +211,7 @@
             "objectclass: top",
             "objectclass: groupOfNames",
             "cn: group",
-            "member: uid=user.1,ou=People,o=test",
+            "member: uid=user.3,ou=People,o=test",
             "",
             "dn: uid=superuser,ou=admins,o=test",
             "objectClass: top",
@@ -246,6 +246,7 @@
             "sn: 1",
             "cn: User1",
             "l: Austin",
+            "manager: cn=group,ou=People,o=test",
             "userPassword: password",
             "",
             "dn: uid=user.2,ou=People,o=test",
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
index cfc978b..deb0662 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -46,6 +46,19 @@
 
 
   private static final
+  String grpAttrAci = "(targetattr=\"*\")" +
+        "(version 3.0; acl \"user attr URL example\"; " +
+        "allow (search,read) " +
+        "userattr=\"ldap:///ou=People,o=test?manager#GROUPDN\";)";
+
+
+  private static final
+  String grp1AttrAci = "(targetattr=\"*\")" +
+        "(version 3.0; acl \"user attr1 URL example\"; " +
+        "allow (search,read) " +
+        "userattr=\"ldap:///ou=People1,o=test?manager#GROUPDN\";)";
+
+  private static final
   String starAciAttrs = "(targetattr=\"* || aci\")" +
           "(version 3.0;acl \"read/search all user, aci op\";" +
           "allow (search, read) " +
@@ -323,6 +336,32 @@
     deleteAttrFromEntry(user1, "aci");
   }
 
+  /**
+   * Test two scenerios with userattr LDAP URL and groupdn keyword.
+   *
+   * @throws Exception Exception If test result is unexpected.
+   */
+  @Test()
+  public void testTargetAttrGrpDN() throws Exception {
+    String aciLdif=makeAddAciLdif("aci", user1, grpAttrAci);
+    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);
+    Assert.assertTrue(attrMap.containsKey("l"));
+    Assert.assertTrue(attrMap.containsKey("sn"));
+    Assert.assertTrue(attrMap.containsKey("uid"));
+    deleteAttrFromEntry(user1, "aci");
+    String aciLdif1=makeAddAciLdif("aci", user1, grp1AttrAci);
+    modEntries(aciLdif1, DIR_MGR_DN, PWD);
+    String userResults1 =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, filter, attrList);
+    //This search should return nothing since the URL has a bogus DN.
+    Assert.assertTrue(userResults1.equals(""));
+  }
 
   private void
   checkAttributeVal(HashMap<String, String> attrMap, String attr,

--
Gitblit v1.10.0