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

neil_a_wilson
14.10.2007 f59baa7abea806ac6d93c8059bfddb60b3acc06d
Add support for the groupOfEntries group type as defined in
draft-findlay-ldap-groupofentries. Entries with the groupOfEntries object
class should be treated in a manner that is virtually identical to entries with
the groupOfNames object class (technically, groupOfNames does not allow
zero-member groups, but the OpenDS implementation does allow this).

OpenDS Issue Number: 2277
4 files modified
279 ■■■■■ changed files
opendj-sdk/opends/resource/schema/00-core.ldif 11 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/extensions/StaticGroup.java 38 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java 16 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java 214 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/resource/schema/00-core.ldif
@@ -433,10 +433,10 @@
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 1274' )
attributeTypes: ( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 1274' )
attributeTypes: ( 2.16.840.1.113730.3.1.602 NAME 'entryDN'
  DESC 'DN of the entry' EQUALITY distinguishedNameMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION
  USAGE directoryOperation X-ORIGIN 'draft-zeilenga-ldap-entrydn' )
attributeTypes: ( 1.3.6.1.1.20 NAME 'entryDN' DESC 'DN of the entry'
  EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
  SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation
  X-ORIGIN 'RFC 5020' )
attributeTypes: ( 1.3.6.1.4.1.453.16.2.103 NAME 'numSubordinates'
  DESC 'Count of immediate subordinates'
  EQUALITY integerMatch ORDERING integerOrderingMatch
@@ -622,4 +622,7 @@
objectClasses: ( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData' SUP top
  MUST dSAQuality MAY ( subtreeMinimumQuality $ subtreeMaximumQuality )
  X-ORIGIN 'RFC 1274' )
objectClasses: ( 1.2.826.0.1.3458854.2.1.1 NAME 'groupOfEntries' SUP top
  STRUCTURAL MUST cn MAY ( member $ businessCategory $ seeAlso $ owner $ ou $
  o $ description ) X-ORIGIN 'draft-findlay-ldap-groupofentries' )
opendj-sdk/opends/src/server/org/opends/server/extensions/StaticGroup.java
@@ -171,12 +171,33 @@
    // Determine whether it is a groupOfNames or groupOfUniqueNames entry.  If
    // neither, then that's a problem.
    AttributeType memberAttributeType;
    ObjectClass groupOfEntriesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_ENTRIES_LC, true);
    ObjectClass groupOfNamesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_NAMES_LC, true);
    ObjectClass groupOfUniqueNamesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_UNIQUE_NAMES_LC, true);
    if (groupEntry.hasObjectClass(groupOfEntriesClass))
    {
    if (groupEntry.hasObjectClass(groupOfNamesClass))
    {
        Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
            get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_ENTRIES,
                OC_GROUP_OF_NAMES);
        throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
      }
      else if (groupEntry.hasObjectClass(groupOfUniqueNamesClass))
      {
        Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
            get(String.valueOf(groupEntry.getDN()), OC_GROUP_OF_ENTRIES,
                OC_GROUP_OF_UNIQUE_NAMES);
        throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
      }
      memberAttributeType = DirectoryConfig.getAttributeType(ATTR_MEMBER, true);
    }
    else if (groupEntry.hasObjectClass(groupOfNamesClass))
    {
      if (groupEntry.hasObjectClass(groupOfUniqueNamesClass))
      {
        Message message = ERR_STATICGROUP_INVALID_OC_COMBINATION.
@@ -247,7 +268,8 @@
    // FIXME -- This needs to exclude enhanced groups once we have support for
    // them.
    String filterString =
         "(&(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames))" +
         "(&(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)" +
            "(objectClass=groupOfEntries))" +
            "(!(objectClass=ds-virtual-static-group)))";
    return SearchFilter.createFilterFromString(filterString);
  }
@@ -271,11 +293,23 @@
      return false;
    }
    ObjectClass groupOfEntriesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_ENTRIES_LC, true);
    ObjectClass groupOfNamesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_NAMES_LC, true);
    ObjectClass groupOfUniqueNamesClass =
         DirectoryConfig.getObjectClass(OC_GROUP_OF_UNIQUE_NAMES_LC, true);
    if (entry.hasObjectClass(groupOfNamesClass))
    if (entry.hasObjectClass(groupOfEntriesClass))
    {
      if (entry.hasObjectClass(groupOfNamesClass) ||
          entry.hasObjectClass(groupOfUniqueNamesClass))
      {
        return false;
      }
      return true;
    }
    else if (entry.hasObjectClass(groupOfNamesClass))
    {
      if (entry.hasObjectClass(groupOfUniqueNamesClass))
      {
opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -655,6 +655,22 @@
  /**
   * The name of the standard "groupOfEntries" object class, formatted in
   * camelCase.
   */
  public static final String OC_GROUP_OF_ENTRIES = "groupOfEntries";
  /**
   * The name of the standard "groupOfEntries" object class, formatted in all
   * lowercase characters.
   */
  public static final String OC_GROUP_OF_ENTRIES_LC = "groupofentries";
  /**
   * The name of the standard "groupOfNames" object class, formatted in
   * camelCase.
   */
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
@@ -1002,6 +1002,200 @@
  /**
   * Tests that the server properly handles adding, deleting, and modifying a
   * static group based on the groupOfEntries object class where that group
   * contains valid members.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testValidPopulatedGroupOfEntries()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    GroupManager groupManager = DirectoryServer.getGroupManager();
    groupManager.deregisterAllGroups();
    TestCaseUtils.addEntries(
      "dn: ou=People,o=test",
      "objectClass: top",
      "objectClass: organizationalUnit",
      "ou: People",
      "",
      "dn: ou=Groups,o=test",
      "objectClass: top",
      "objectClass: organizationalUnit",
      "ou: Groups",
      "",
      "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",
      "cn: User 3",
      "userPassword: password");
    // Make sure that there aren't any groups registered with the server.
    assertFalse(groupManager.getGroupInstances().iterator().hasNext());
    // Add a new static group to the server and make sure it gets registered
    // with the group manager.
    TestCaseUtils.addEntry(
      "dn: cn=Test Group of Entries,ou=Groups,o=test",
      "objectClass: top",
      "objectClass: groupOfEntries",
      "cn: Test Group of Entries",
      "member: uid=user.1,ou=People,o=test",
      "member: uid=user.2,ou=People,o=test");
    // Perform a basic set of validation on the group itself.
    DN groupDN = DN.decode("cn=Test Group of Entries,ou=Groups,o=test");
    DN user1DN = DN.decode("uid=user.1,ou=People,o=test");
    DN user2DN = DN.decode("uid=user.2,ou=People,o=test");
    DN user3DN = DN.decode("uid=user.3,ou=People,o=test");
    Group groupInstance = groupManager.getGroupInstance(groupDN);
    assertNotNull(groupInstance);
    assertEquals(groupInstance.getGroupDN(), groupDN);
    assertTrue(groupInstance.isMember(user1DN));
    assertTrue(groupInstance.isMember(user2DN));
    assertFalse(groupInstance.isMember(user3DN));
    MemberList memberList = groupInstance.getMembers();
    while (memberList.hasMoreMembers())
    {
      DN memberDN = memberList.nextMemberDN();
      assertTrue(memberDN.equals(user1DN) || memberDN.equals(user2DN));
    }
    SearchFilter filter = SearchFilter.createFilterFromString("(uid=user.1)");
    memberList = groupInstance.getMembers(DN.decode("o=test"),
                                          SearchScope.WHOLE_SUBTREE, filter);
    assertTrue(memberList.hasMoreMembers());
    DN memberDN = memberList.nextMemberDN();
    assertTrue(memberDN.equals(user1DN));
    assertFalse(memberList.hasMoreMembers());
    filter = SearchFilter.createFilterFromString("(uid=user.3)");
    memberList = groupInstance.getMembers(DN.decode("o=test"),
                                          SearchScope.WHOLE_SUBTREE, filter);
    assertFalse(memberList.hasMoreMembers());
    // Modify the group and make sure the group manager gets updated
    // accordingly.
    LinkedList<Modification> mods = new LinkedList<Modification>();
    Attribute a2 = new Attribute("member", "uid=user.2,ou=People,o=test");
    Attribute a3 = new Attribute("member", "uid=user.3,ou=People,o=test");
    mods.add(new Modification(ModificationType.DELETE, a2));
    mods.add(new Modification(ModificationType.ADD, a3));
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyOperation modifyOperation = conn.processModify(groupDN, mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    groupInstance = groupManager.getGroupInstance(groupDN);
    assertNotNull(groupInstance);
    assertEquals(groupInstance.getGroupDN(), groupDN);
    assertTrue(groupInstance.isMember(user1DN));
    assertFalse(groupInstance.isMember(user2DN));
    assertTrue(groupInstance.isMember(user3DN));
    // Delete the group and make sure the group manager gets updated
    // accordingly.
    DeleteOperation deleteOperation = conn.processDelete(groupDN);
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    assertNull(groupManager.getGroupInstance(groupDN));
  }
  /**
   * Tests that the server properly handles a groupOfEntries object that doesn't
   * contain any members.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testValidEmptyGroupOfEntries()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    GroupManager groupManager = DirectoryServer.getGroupManager();
    groupManager.deregisterAllGroups();
    TestCaseUtils.addEntry(
      "dn: ou=Groups,o=test",
      "objectClass: top",
      "objectClass: organizationalUnit",
      "ou: Groups");
    // Make sure that there aren't any groups registered with the server.
    assertFalse(groupManager.getGroupInstances().iterator().hasNext());
    // Add a new static group to the server and make sure it gets registered
    // with the group manager.
    TestCaseUtils.addEntry(
      "dn: cn=Test Group of Entries,ou=Groups,o=test",
      "objectClass: top",
      "objectClass: groupOfEntries",
      "cn: Test Group of Names");
    // Make sure that the group exists but doesn't have any members.
    DN groupDN = DN.decode("cn=Test Group of Entries,ou=Groups,o=test");
    Group groupInstance = groupManager.getGroupInstance(groupDN);
    assertNotNull(groupInstance);
    assertEquals(groupInstance.getGroupDN(), groupDN);
    assertFalse(groupInstance.getMembers().hasMoreMembers());
    // Delete the group and make sure the group manager gets updated
    // accordingly.
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation = conn.processDelete(groupDN);
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    assertNull(groupManager.getGroupInstance(groupDN));
  }
  /**
   * Verifies that the group manager properly handles modify DN operations on
   * static group entries.
   *
@@ -1170,13 +1364,21 @@
      "objectClass: groupOfUniqueNames",
      "cn: Group 3",
      "uniqueMember: uid=user.1,ou=People,o=test",
      "uniqueMember: uid=user.3,ou=People,o=test");
      "uniqueMember: uid=user.3,ou=People,o=test",
      "",
      "dn: cn=Group 4,ou=Groups,o=test",
      "objectClass: top",
      "objectClass: groupOfEntries",
      "cn: Group 4",
      "member: uid=user.1,ou=People,o=test",
      "member: uid=user.2,ou=People,o=test");
    // Perform basic validation on the groups.
    DN group1DN = DN.decode("cn=Group 1,ou=Groups,o=test");
    DN group2DN = DN.decode("cn=Group 2,ou=Groups,o=test");
    DN group3DN = DN.decode("cn=Group 3,ou=Groups,o=test");
    DN group4DN = DN.decode("cn=Group 4,ou=Groups,o=test");
    DN user1DN  = DN.decode("uid=user.1,ou=People,o=test");
    DN user2DN  = DN.decode("uid=user.2,ou=People,o=test");
    DN user3DN  = DN.decode("uid=user.3,ou=People,o=test");
@@ -1184,6 +1386,7 @@
    Group group1 = groupManager.getGroupInstance(group1DN);
    Group group2 = groupManager.getGroupInstance(group2DN);
    Group group3 = groupManager.getGroupInstance(group3DN);
    Group group4 = groupManager.getGroupInstance(group4DN);
    assertNotNull(group1);
    assertTrue(group1.isMember(user1DN));
@@ -1200,6 +1403,11 @@
    assertFalse(group3.isMember(user2DN));
    assertTrue(group3.isMember(user3DN));
    assertNotNull(group4);
    assertTrue(group4.isMember(user1DN));
    assertTrue(group4.isMember(user2DN));
    assertFalse(group4.isMember(user3DN));
    // Get a client connection authenticated as user1 and make sure it handles
    // group operations correctly.
@@ -1332,6 +1540,10 @@
    deleteOperation = conn.processDelete(group3DN);
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    assertNull(groupManager.getGroupInstance(group3DN));
    deleteOperation = conn.processDelete(group4DN);
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    assertNull(groupManager.getGroupInstance(group3DN));
  }