From 2021fe3e69527d25fb1b2dc67e4e931e6a56260a Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 13 Apr 2007 15:59:03 +0000
Subject: [PATCH] Update the member virtual attribute implementation so that it provides a mechanism for preventing the entire member list from being returned, which can be a very expensive operation.  When running with this configuration, the attribute will handle requests that determine whether a given user is a member of the group, but will not list the entire set of membership.

---
 opends/resource/schema/02-config.ldif                                                                  |    7 ++
 opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java                     |   47 ++++++++++++++-
 opends/src/admin/defn/org/opends/server/admin/std/MemberVirtualAttributeConfiguration.xml              |   42 ++++++++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java |   59 +++++++++++++++++++
 opends/resource/config/config.ldif                                                                     |    4 +
 opends/tests/unit-tests-testng/resource/config-changes.ldif                                            |   10 +++
 6 files changed, 166 insertions(+), 3 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index 9752405..9b6458b 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1741,22 +1741,26 @@
 dn: cn=Virtual Static member,cn=Virtual Attributes,cn=config
 objectClass: top
 objectClass: ds-cfg-virtual-attribute
+objectClass: ds-cfg-member-virtual-attribute
 cn: Virtual Static member
 ds-cfg-virtual-attribute-class: org.opends.server.extensions.MemberVirtualAttributeProvider
 ds-cfg-virtual-attribute-enabled: true
 ds-cfg-virtual-attribute-type: member
 ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real
 ds-cfg-virtual-attribute-filter: (&(objectClass=groupOfNames)(objectClass=ds-virtual-static-group))
+ds-cfg-allow-retrieving-membership: false
 
 dn: cn=Virtual Static uniqueMember,cn=Virtual Attributes,cn=config
 objectClass: top
 objectClass: ds-cfg-virtual-attribute
+objectClass: ds-cfg-member-virtual-attribute
 cn: Virtual Static uniqueMember
 ds-cfg-virtual-attribute-class: org.opends.server.extensions.MemberVirtualAttributeProvider
 ds-cfg-virtual-attribute-enabled: true
 ds-cfg-virtual-attribute-type: uniqueMember
 ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real
 ds-cfg-virtual-attribute-filter: (&(objectClass=groupOfUniqueNames)(objectClass=ds-virtual-static-group))
+ds-cfg-allow-retrieving-membership: false
 
 dn: cn=Work Queue,cn=config
 objectClass: top
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 9138149..9dba19d 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -1156,6 +1156,9 @@
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.344
   NAME 'ds-cfg-virtual-attribute-value' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.345
+  NAME 'ds-cfg-allow-retrieving-membership' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+  SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
   MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -1615,4 +1618,8 @@
   NAME 'ds-cfg-user-defined-virtual-attribute' SUP ds-cfg-virtual-attribute
   STRUCTURAL MUST ds-cfg-virtual-attribute-value
   X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.101
+  NAME 'ds-cfg-member-virtual-attribute' SUP ds-cfg-virtual-attribute
+  STRUCTURAL MUST ds-cfg-allow-retrieving-membership
+  X-ORIGIN 'OpenDS Directory Server' )
 
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/MemberVirtualAttributeConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/MemberVirtualAttributeConfiguration.xml
new file mode 100644
index 0000000..ea649c0
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/MemberVirtualAttributeConfiguration.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<adm:managed-object name="member-virtual-attribute"
+plural-name="user-defined-virtual-attributes"
+package="org.opends.server.admin.std" extends="virtual-attribute"
+xmlns:adm="http://www.opends.org/admin"
+xmlns:ldap="http://www.opends.org/admin-ldap">
+  <adm:synopsis>
+    The
+    <adm:user-friendly-name />
+    is used to generate a member or uniqueMember attribute whose values are the
+    DNs of the members of a specified group.  This is used to implement virtual
+    static group functionality, in which it is possible to create an entry which
+    looks like a static group but obtains all of its membership from a dynamic
+    group (or some other type of group, including another static group).
+  </adm:synopsis>
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:oid>1.3.6.1.4.1.26027.1.2.101</ldap:oid>
+      <ldap:name>ds-cfg-member-virtual-attribute</ldap:name>
+      <ldap:superior>ds-cfg-virtual-attribute</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+  <adm:property name="allow-retrieving-membership" mandatory="true">
+    <adm:synopsis>
+      Indicates whether to handle requests that request all values for the
+      virtual attribute.  This can be a very expensive operation in some cases,
+      and is not in-line with the primary function of virtual static groups,
+      which is to make it possible to use static group idioms to determine
+      whether a given user is a member.
+    </adm:synopsis>
+    <adm:syntax>
+      <adm:boolean />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:oid>1.3.6.1.4.1.26027.1.1.345</ldap:oid>
+        <ldap:name>ds-cfg-allow-retrieving-membership</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+</adm:managed-object>
+
diff --git a/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java b/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
index 6bbf9c1..1432512 100644
--- a/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
+++ b/opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
@@ -32,7 +32,8 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 
-import org.opends.server.admin.std.server.VirtualAttributeCfg;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.MemberVirtualAttributeCfg;
 import org.opends.server.api.Group;
 import org.opends.server.api.VirtualAttributeProvider;
 import org.opends.server.config.ConfigException;
@@ -42,6 +43,7 @@
 import org.opends.server.types.AttributeValue;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConditionResult;
+import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
@@ -62,12 +64,16 @@
  * uniqueMember attribute.
  */
 public class MemberVirtualAttributeProvider
-       extends VirtualAttributeProvider<VirtualAttributeCfg>
+       extends VirtualAttributeProvider<MemberVirtualAttributeCfg>
+       implements ConfigurationChangeListener<MemberVirtualAttributeCfg>
 {
   // The attribute type used to indicate which target group should be used to
   // obtain the member list.
   private AttributeType targetGroupType;
 
+  // The current configuration for this member virtual attribute.
+  private MemberVirtualAttributeCfg currentConfig;
+
 
 
   /**
@@ -88,9 +94,12 @@
    */
   @Override()
   public void initializeVirtualAttributeProvider(
-                            VirtualAttributeCfg configuration)
+                            MemberVirtualAttributeCfg configuration)
          throws ConfigException, InitializationException
   {
+    configuration.addMemberChangeListener(this);
+    currentConfig = configuration;
+
     targetGroupType =
          DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true);
   }
@@ -115,6 +124,11 @@
   public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                  VirtualAttributeRule rule)
   {
+    if (! currentConfig.isAllowRetrievingMembership())
+    {
+      return new LinkedHashSet<AttributeValue>(0);
+    }
+
     Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN());
     if (g == null)
     {
@@ -336,5 +350,32 @@
     searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
     return;
   }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isConfigurationChangeAcceptable(
+                      MemberVirtualAttributeCfg configuration,
+                      List<String> unacceptableReasons)
+  {
+    // The new configuration should always be acceptable.
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public ConfigChangeResult applyConfigurationChange(
+                                 MemberVirtualAttributeCfg configuration)
+  {
+    // Just accept the new configuration as-is.
+    currentConfig = configuration;
+
+    return new ConfigChangeResult(ResultCode.SUCCESS, false);
+  }
 }
 
diff --git a/opends/tests/unit-tests-testng/resource/config-changes.ldif b/opends/tests/unit-tests-testng/resource/config-changes.ldif
index 328fb33..1aa7cf1 100644
--- a/opends/tests/unit-tests-testng/resource/config-changes.ldif
+++ b/opends/tests/unit-tests-testng/resource/config-changes.ldif
@@ -525,3 +525,13 @@
 ds-cfg-database-checkpointer-wakeup-interval: 30 seconds
 ds-cfg-database-lock-num-lock-tables: 19
 
+dn: cn=Virtual Static member,cn=Virtual Attributes,cn=config
+changetype: modify
+replace: ds-cfg-allow-retrieving-membership
+ds-cfg-allow-retrieving-membership: true
+
+dn: cn=Virtual Static uniqueMember,cn=Virtual Attributes,cn=config
+changetype: modify
+replace: ds-cfg-allow-retrieving-membership
+ds-cfg-allow-retrieving-membership: true
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
index fc43be7..0b5a832 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
@@ -837,6 +837,65 @@
 
 
   /**
+   * Tests the behavior of the member virtual attribute with different settings
+   * for the "allow retrieving membership" attribute.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testAllowRetrievingMembership()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntries(LDIF_LINES);
+
+    Entry e = DirectoryServer.getEntry(vmd1);
+    assertNotNull(e);
+    assertTrue(e.hasAttribute(memberType));
+
+    Attribute a = e.getAttribute(memberType).get(0);
+    assertEquals(a.getValues().size(), 1);
+
+    AttributeValue v = new AttributeValue(memberType, u4.toString());
+    assertTrue(a.hasValue(v));
+
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+
+    LinkedList<Modification> mods = new LinkedList<Modification>();
+    mods.add(new Modification(ModificationType.REPLACE,
+         new Attribute("ds-cfg-allow-retrieving-membership", "false")));
+    DN definitionDN =
+         DN.decode("cn=Virtual Static member,cn=Virtual Attributes,cn=config");
+    ModifyOperation modifyOperation = conn.processModify(definitionDN, mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    e = DirectoryServer.getEntry(vmd1);
+    assertNotNull(e);
+    assertTrue(e.hasAttribute(memberType));
+
+    a = e.getAttribute(memberType).get(0);
+    assertEquals(a.getValues().size(), 0);
+
+    v = new AttributeValue(memberType, u4.toString());
+    assertTrue(a.hasValue(v));
+
+
+    mods = new LinkedList<Modification>();
+    mods.add(new Modification(ModificationType.REPLACE,
+         new Attribute("ds-cfg-allow-retrieving-membership", "true")));
+    modifyOperation = conn.processModify(definitionDN, mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    cleanUp();
+  }
+
+
+
+  /**
    * Removes all of the groups that have been added to the server.
    *
    * @throws  Exception  If an unexpected problem occurs.

--
Gitblit v1.10.0