opends/resource/config/config.ldif
@@ -441,6 +441,13 @@ ds-cfg-group-implementation-class: org.opends.server.extensions.StaticGroup ds-cfg-group-implementation-enabled: true dn: cn=Virtual Static,cn=Group Implementations,cn=config objectClass: top objectClass: ds-cfg-group-implementation cn: Virtual Static ds-cfg-group-implementation-class: org.opends.server.extensions.VirtualStaticGroup ds-cfg-group-implementation-enabled: true dn: cn=Identity Mappers,cn=config objectClass: top objectClass: ds-cfg-branch @@ -1731,6 +1738,26 @@ ds-cfg-virtual-attribute-type: subschemaSubentry ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real dn: cn=Virtual Static member,cn=Virtual Attributes,cn=config objectClass: top objectClass: ds-cfg-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)) dn: cn=Virtual Static uniqueMember,cn=Virtual Attributes,cn=config objectClass: top objectClass: ds-cfg-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)) dn: cn=Work Queue,cn=config objectClass: top objectClass: ds-cfg-work-queue opends/resource/schema/02-config.ldif
@@ -1150,6 +1150,9 @@ NAME 'ds-task-rebuild-max-threads' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.343 NAME 'ds-target-group-dn' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 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 ) @@ -1602,5 +1605,8 @@ MUST ( ds-task-rebuild-base-dn $ ds-task-rebuild-index ) MAY ( ds-task-rebuild-max-threads ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.99 NAME 'ds-virtual-static-group' SUP top AUXILIARY MUST ds-target-group-dn X-ORIGIN 'OpenDS Directory Server' ) opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
New file @@ -0,0 +1,349 @@ /* * 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.extensions; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import org.opends.server.admin.std.server.VirtualAttributeCfg; import org.opends.server.api.Group; import org.opends.server.api.VirtualAttributeProvider; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.core.SearchOperation; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.ByteString; import org.opends.server.types.ConditionResult; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.MemberList; import org.opends.server.types.MembershipException; import org.opends.server.types.ResultCode; import org.opends.server.types.VirtualAttributeRule; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.ServerConstants.*; /** * This class implements a virtual attribute provider that works in conjunction * with virtual static groups to generate the values for the member or * uniqueMember attribute. */ public class MemberVirtualAttributeProvider extends VirtualAttributeProvider<VirtualAttributeCfg> { // The attribute type used to indicate which target group should be used to // obtain the member list. private AttributeType targetGroupType; /** * Creates a new instance of this member virtual attribute provider. */ public MemberVirtualAttributeProvider() { super(); // All initialization should be performed in the // initializeVirtualAttributeProvider method. } /** * {@inheritDoc} */ @Override() public void initializeVirtualAttributeProvider( VirtualAttributeCfg configuration) throws ConfigException, InitializationException { targetGroupType = DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true); } /** * {@inheritDoc} */ @Override() public boolean isMultiValued() { return true; } /** * {@inheritDoc} */ @Override() public LinkedHashSet<AttributeValue> getValues(Entry entry, VirtualAttributeRule rule) { Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN()); if (g == null) { return new LinkedHashSet<AttributeValue>(0); } LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(); try { MemberList memberList = g.getMembers(); while (memberList.hasMoreMembers()) { try { DN memberDN = memberList.nextMemberDN(); if (memberDN != null) { values.add(new AttributeValue(rule.getAttributeType(), memberDN.toString())); } } catch (MembershipException me) { if (! me.continueIterating()) { break; } } } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } } return values; } /** * {@inheritDoc} */ @Override() public boolean hasValue(Entry entry, VirtualAttributeRule rule) { Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN()); if (g == null) { return false; } try { MemberList memberList = g.getMembers(); while (memberList.hasMoreMembers()) { try { DN memberDN = memberList.nextMemberDN(); if (memberDN != null) { memberList.close(); return true; } } catch (MembershipException me) { if (! me.continueIterating()) { break; } } } } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } } return false; } /** * {@inheritDoc} */ @Override() public boolean hasValue(Entry entry, VirtualAttributeRule rule, AttributeValue value) { Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN()); if (g == null) { return false; } try { return g.isMember(DN.decode(value.getValue())); } catch (Exception e) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, e); } } return false; } /** * {@inheritDoc} */ @Override() public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule, Collection<AttributeValue> values) { for (AttributeValue v : values) { if (hasValue(entry, rule, v)) { return true; } } return false; } /** * {@inheritDoc} */ @Override() public ConditionResult matchesSubstring(Entry entry, VirtualAttributeRule rule, ByteString subInitial, List<ByteString> subAny, ByteString subFinal) { // DNs cannot be used in substring matching. return ConditionResult.UNDEFINED; } /** * {@inheritDoc} */ @Override() public ConditionResult greaterThanOrEqualTo(Entry entry, VirtualAttributeRule rule, AttributeValue value) { // DNs cannot be used in ordering matching. return ConditionResult.UNDEFINED; } /** * {@inheritDoc} */ @Override() public ConditionResult lessThanOrEqualTo(Entry entry, VirtualAttributeRule rule, AttributeValue value) { // DNs cannot be used in ordering matching. return ConditionResult.UNDEFINED; } /** * {@inheritDoc} */ @Override() public ConditionResult approximatelyEqualTo(Entry entry, VirtualAttributeRule rule, AttributeValue value) { // DNs cannot be used in approximate matching. return ConditionResult.UNDEFINED; } /** * {@inheritDoc}. This virtual attribute will support search operations only * if one of the following is true about the search filter: * <UL> * <LI>It is an equality filter targeting the associated attribute * type.</LI> * <LI>It is an AND filter in which at least one of the components is an * equality filter targeting the associated attribute type.</LI> * <LI>It is an OR filter in which all of the components are equality * filters targeting the associated attribute type.</LI> * </UL> */ @Override() public boolean isSearchable(VirtualAttributeRule rule, SearchOperation searchOperation) { return false; } /** * {@inheritDoc} */ @Override() public void processSearch(VirtualAttributeRule rule, SearchOperation searchOperation) { searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); return; } } opends/src/server/org/opends/server/extensions/StaticGroup.java
@@ -79,9 +79,6 @@ public class StaticGroup extends Group { // The attribute type used to hold the membership list for this group. private AttributeType memberAttributeType; @@ -241,7 +238,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=ds-virtual-static-group))"; return SearchFilter.createFilterFromString(filterString); } @@ -257,6 +255,13 @@ // FIXME -- This needs to exclude enhanced groups once we have support for //them. ObjectClass virtualStaticGroupClass = DirectoryConfig.getObjectClass(OC_VIRTUAL_STATIC_GROUP, true); if (entry.hasObjectClass(virtualStaticGroupClass)) { return false; } ObjectClass groupOfNamesClass = DirectoryConfig.getObjectClass(OC_GROUP_OF_NAMES_LC, true); ObjectClass groupOfUniqueNamesClass = opends/src/server/org/opends/server/extensions/VirtualStaticGroup.java
New file @@ -0,0 +1,484 @@ /* * 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.extensions; import java.util.Collections; import java.util.List; import org.opends.server.api.Group; import org.opends.server.core.DirectoryServer; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.MemberList; import org.opends.server.types.ObjectClass; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchFilter; import org.opends.server.types.SearchScope; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.messages.ExtensionsMessages.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.Validator.*; /** * This class provides a virtual static group implementation, in which * membership is based on membership of another group. */ public class VirtualStaticGroup extends Group { // The DN of the entry that holds the definition for this group. private DN groupEntryDN; // The DN of the target group that will provide membership information. private DN targetGroupDN; /** * Creates a new, uninitialized virtual static group instance. This is * intended for internal use only. */ public VirtualStaticGroup() { super(); // No initialization is required here. } /** * Creates a new virtual static group instance with the provided information. * * @param groupEntryDN The DN of the entry that holds the definition for * this group. It must not be {@code null}. * @param targetGroupDN The DN of the target group that will provide * membership information. It must not be * {@code null}. */ public VirtualStaticGroup(DN groupEntryDN, DN targetGroupDN) { super(); ensureNotNull(groupEntryDN, targetGroupDN); this.groupEntryDN = groupEntryDN; this.targetGroupDN = targetGroupDN; } /** * {@inheritDoc} */ @Override() public void initializeGroupImplementation(ConfigEntry configEntry) throws ConfigException, InitializationException { // No additional initialization is required. } /** * {@inheritDoc} */ @Override() public VirtualStaticGroup newInstance(Entry groupEntry) throws DirectoryException { ensureNotNull(groupEntry); // Get the target group DN attribute from the entry, if there is one. DN targetDN = null; AttributeType targetType = DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true); List<Attribute> attrList = groupEntry.getAttribute(targetType); if (attrList != null) { for (Attribute a : attrList) { for (AttributeValue v : a.getValues()) { if (targetDN != null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_MULTIPLE_TARGETS; String message = getMessage(msgID, String.valueOf(groupEntry.getDN())); throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message, msgID); } try { targetDN = DN.decode(v.getValue()); } catch (DirectoryException de) { if (debugEnabled()) { debugCaught(DebugLogLevel.ERROR, de); } int msgID = MSGID_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET; String message = getMessage(msgID, v.getStringValue(), String.valueOf(groupEntry.getDN()), de.getErrorMessage()); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, msgID, de); } } } } if (targetDN == null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET; String message = getMessage(msgID, String.valueOf(groupEntry.getDN())); throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message, msgID); } return new VirtualStaticGroup(groupEntry.getDN(), targetDN); } /** * {@inheritDoc} */ @Override() public SearchFilter getGroupDefinitionFilter() throws DirectoryException { // FIXME -- This needs to exclude enhanced groups once we have support for // them. return SearchFilter.createFilterFromString("(" + ATTR_OBJECTCLASS + "=" + OC_VIRTUAL_STATIC_GROUP + ")"); } /** * {@inheritDoc} */ @Override() public boolean isGroupDefinition(Entry entry) { ensureNotNull(entry); // FIXME -- This needs to exclude enhanced groups once we have support for //them. ObjectClass virtualStaticGroupClass = DirectoryServer.getObjectClass(OC_VIRTUAL_STATIC_GROUP, true); return entry.hasObjectClass(virtualStaticGroupClass); } /** * {@inheritDoc} */ @Override() public DN getGroupDN() { return groupEntryDN; } /** * Retrieves the DN of the target group for this virtual static group. * * @return The DN of the target group for this virtual static group. */ public DN getTargetGroupDN() { return targetGroupDN; } /** * {@inheritDoc} */ @Override() public boolean supportsNestedGroups() { // Dynamic groups don't support nesting. return false; } /** * {@inheritDoc} */ @Override() public List<DN> getNestedGroupDNs() { // Dynamic groups don't support nesting. return Collections.<DN>emptyList(); } /** * {@inheritDoc} */ @Override() public void addNestedGroup(DN nestedGroupDN) throws UnsupportedOperationException, DirectoryException { // Dynamic groups don't support nesting. int msgID = MSGID_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED; String message = getMessage(msgID); throw new UnsupportedOperationException(message); } /** * {@inheritDoc} */ @Override() public void removeNestedGroup(DN nestedGroupDN) throws UnsupportedOperationException, DirectoryException { // Dynamic groups don't support nesting. int msgID = MSGID_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED; String message = getMessage(msgID); throw new UnsupportedOperationException(message); } /** * {@inheritDoc} */ @Override() public boolean isMember(DN userDN) throws DirectoryException { Group targetGroup = DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); if (targetGroup == null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP; String message = getMessage(msgID, String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, msgID); } else if (targetGroup instanceof VirtualStaticGroup) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL; String message = getMessage(msgID, String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, msgID); } else { return targetGroup.isMember(userDN); } } /** * {@inheritDoc} */ @Override() public boolean isMember(Entry userEntry) throws DirectoryException { Group targetGroup = DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); if (targetGroup == null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP; String message = getMessage(msgID, String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, msgID); } else if (targetGroup instanceof VirtualStaticGroup) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL; String message = getMessage(msgID, String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, msgID); } else { return targetGroup.isMember(userEntry); } } /** * {@inheritDoc} */ @Override() public MemberList getMembers() throws DirectoryException { Group targetGroup = DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); if (targetGroup == null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP; String message = getMessage(msgID, String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, msgID); } else if (targetGroup instanceof VirtualStaticGroup) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL; String message = getMessage(msgID, String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, msgID); } else { return targetGroup.getMembers(); } } /** * {@inheritDoc} */ @Override() public MemberList getMembers(DN baseDN, SearchScope scope, SearchFilter filter) throws DirectoryException { Group targetGroup = DirectoryServer.getGroupManager().getGroupInstance(targetGroupDN); if (targetGroup == null) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP; String message = getMessage(msgID, String.valueOf(targetGroupDN), String.valueOf(groupEntryDN)); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, msgID); } else if (targetGroup instanceof VirtualStaticGroup) { int msgID = MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL; String message = getMessage(msgID, String.valueOf(groupEntryDN), String.valueOf(targetGroupDN)); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, msgID); } else { return targetGroup.getMembers(baseDN, scope, filter); } } /** * {@inheritDoc} */ @Override() public boolean mayAlterMemberList() { return false; } /** * {@inheritDoc} */ @Override() public void addMember(Entry userEntry) throws UnsupportedOperationException, DirectoryException { // Dynamic groups don't support altering the member list. int msgID = MSGID_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED; String message = getMessage(msgID, String.valueOf(groupEntryDN)); throw new UnsupportedOperationException(message); } /** * {@inheritDoc} */ @Override() public void removeMember(DN userDN) throws UnsupportedOperationException, DirectoryException { // Dynamic groups don't support altering the member list. int msgID = MSGID_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED; String message = getMessage(msgID, String.valueOf(groupEntryDN)); throw new UnsupportedOperationException(message); } /** * {@inheritDoc} */ @Override() public void toString(StringBuilder buffer) { buffer.append("VirtualStaticGroup(dn="); buffer.append(groupEntryDN); buffer.append(",targetGroupDN="); buffer.append(targetGroupDN); buffer.append(")"); } } opends/src/server/org/opends/server/messages/ExtensionsMessages.java
@@ -4941,6 +4941,78 @@ /** * The message ID for the message that will be used if the virtual static * group has multiple targets. This takes a single argument, which is the DN * of the group. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_MULTIPLE_TARGETS = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 470; /** * The message ID for the message that will be used if the virtual static * group has a target that can't be decoded as a DN. This takes three * arguments, which are the target group value, the group DN, and a message * explaining the problem that occurred. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 471; /** * The message ID for the message that will be used if the virtual static * group does not have a target group DN. This takes a single argument, which * is the DN of the group. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 472; /** * The message ID for the message that will be used if an attempt is made to * nest a virtual static group. This takes a single argument, which is the * DN of the group. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 473; /** * The message ID for the message that will be used if the target group does * not exist. This takes two arguments, which is the target group DN and the * virtual static group DN. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 474; /** * The message ID for the message that will be used if an attempt is made to * alter the membership for a virtual static group. This takes a single * argument, which is the DN of the group. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED = CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 475; /** * The message ID for the message that will be used if a virtual static group * target is also a virtual static group. This takes two arguments, which are * the object group DN and the target group DN. */ public static final int MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL= CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 476; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -7109,6 +7181,30 @@ "The provided character set definition '%s' is invalid " + "because it contains character '%s' which has already " + "been used."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_MULTIPLE_TARGETS, "The virtual static group defined in entry %s contains " + "multiple target group DNs, but only one is allowed."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_CANNOT_DECODE_TARGET, "Unable to decode \"%s\" as the target DN for group %s: " + "%s."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET, "The virtual static group defined in entry %s does not " + "contain a target group definition."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_NESTING_NOT_SUPPORTED, "Virtual static groups do not support nesting."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_NO_TARGET_GROUP, "Target group %s referenced by virtual static group %s " + "does not exist."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_ALTERING_MEMBERS_NOT_SUPPORTED, "Altering membership for virtual static group %s is not " + "allowed."); registerMessage(MSGID_VIRTUAL_STATIC_GROUP_TARGET_CANNOT_BE_VIRTUAL, "Virtual static group %s references target group %s " + "which is itself a virtual static group. One " + "virtual static group is not allowed to reference " + "another as its target group."); } } opends/src/server/org/opends/server/util/ServerConstants.java
@@ -490,6 +490,14 @@ /** * The name of the attribute that is used to specify the DN of the target * group for a virtual static group. */ public static final String ATTR_TARGET_GROUP_DN = "ds-target-group-dn"; /** * The name of the attribute that is used to specify the total number of * connections established since startup, formatted in camel case. */ @@ -824,6 +832,15 @@ /** * The name of the ds-virtual-static-group objectclass in all lowercase * characters. */ public static final String OC_VIRTUAL_STATIC_GROUP = "ds-virtual-static-group"; /** * The English name for the basic disabled log severity used for all * log severities. */ opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
@@ -43,6 +43,7 @@ import org.opends.server.core.ModifyDNOperation; import org.opends.server.extensions.DynamicGroup; import org.opends.server.extensions.StaticGroup; import org.opends.server.extensions.VirtualStaticGroup; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.types.Attribute; @@ -100,6 +101,7 @@ LinkedHashSet<Class> groupClasses = new LinkedHashSet<Class>(); groupClasses.add(StaticGroup.class); groupClasses.add(DynamicGroup.class); groupClasses.add(VirtualStaticGroup.class); for (Group g : groupManager.getGroupImplementations()) { opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
New file @@ -0,0 +1,859 @@ /* * 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.extensions; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.opends.server.TestCaseUtils; import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn; import org.opends.server.core.DirectoryServer; import org.opends.server.core.GroupManager; import org.opends.server.core.ModifyOperation; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.ConditionResult; import org.opends.server.types.DereferencePolicy; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.MemberList; import org.opends.server.types.Modification; import org.opends.server.types.ModificationType; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchScope; import org.opends.server.types.SearchFilter; import org.opends.server.types.VirtualAttributeRule; import static org.testng.Assert.*; /** * A set of test cases for the virtual static group implementation and the * member virtual attribute provider. */ public class VirtualStaticGroupTestCase extends ExtensionsTestCase { /** * The lines comprising the LDIF test data. */ private static final String[] LDIF_LINES = { "dn: ou=People,o=test", "objectClass: top", "objectClass: organizationalUnit", "ou: People", "", "dn: uid=test.1,ou=People,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.1", "givenName: Test", "sn: 1", "cn: Test 1", "userPassword: password", "", "dn: uid=test.2,ou=People,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.2", "givenName: Test", "sn: 2", "cn: Test 2", "userPassword: password", "", "dn: uid=test.3,ou=People,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.3", "givenName: Test", "sn: 3", "cn: Test 3", "userPassword: password", "", "dn: uid=test.4,ou=People,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.4", "givenName: Test", "sn: 4", "cn: Test 4", "userPassword: password", "", "dn: ou=Groups,o=test", "objectClass: top", "objectClass: organizationalUnit", "ou: Groups", "", "dn: cn=Dynamic All Users,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfURLs", "cn: Dynamic All Users", "memberURL: ldap:///ou=People,o=test??sub?(objectClass=person)", "", "dn: cn=Dynamic One User,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfURLs", "cn: Dynamic One User", "memberURL: ldap:///ou=People,o=test??sub?(&(objectClass=person)(sn=4))", "", "dn: cn=Static member List,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "cn: Static member List", "member: uid=test.1,ou=People,o=test", "member: uid=test.3,ou=People,o=test", "", "dn: cn=Static uniqueMember List,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfUniqueNames", "cn: Static uniqueMember List", "uniqueMember: uid=test.2,ou=People,o=test", "uniqueMember: uid=test.3,ou=People,o=test", "uniqueMember: uid=no-such-user,ou=People,o=test", "", "dn: cn=Virtual member All Users,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Virtual member All Users", "ds-target-group-dn: cn=Dynamic All Users,ou=Groups,o=test", "", "dn: cn=Virtual uniqueMember All Users,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfUniqueNames", "objectClass: ds-virtual-static-group", "cn: Virtual uniqueMember All Users", "ds-target-group-dn: cn=Dynamic All Users,ou=Groups,o=test", "", "dn: cn=Virtual member One User,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Virtual member One User", "ds-target-group-dn: cn=Dynamic One User,ou=Groups,o=test", "", "dn: cn=Virtual uniqueMember One User,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfUniqueNames", "objectClass: ds-virtual-static-group", "cn: Virtual uniqueMember One User", "ds-target-group-dn: cn=Dynamic One User,ou=Groups,o=test", "", "dn: cn=Virtual Static member List,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Virtual Static member List", "ds-target-group-dn: cn=Static member List,ou=Groups,o=test", "", "dn: cn=Virtual Static uniqueMember List,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfUniqueNames", "objectClass: ds-virtual-static-group", "cn: Virtual Static uniqueMember List", "ds-target-group-dn: cn=Static uniqueMember List,ou=Groups,o=test", "", "dn: cn=Crossover member Static Group,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfUniqueNames", "objectClass: ds-virtual-static-group", "cn: Crossover member Static Group", "ds-target-group-dn: cn=Static member List,ou=Groups,o=test", "", "dn: cn=Crossover uniqueMember Static Group,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Crossover uniqueMember Static Group", "ds-target-group-dn: cn=Static uniqueMember List,ou=Groups,o=test", "", "dn: cn=Virtual Nonexistent,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Virtual Nonexistent", "ds-target-group-dn: cn=Nonexistent,ou=Groups,o=test" }; // The attribute type for the member attribute. private AttributeType memberType; // The attribute type for the uniqueMember attribute. private AttributeType uniqueMemberType; // The server group manager. private GroupManager groupManager; // The DNs of the various entries in the data set. private DN u1; private DN u2; private DN u3; private DN u4; private DN da; private DN d1; private DN sm; private DN su; private DN vmda; private DN vuda; private DN vmd1; private DN vud1; private DN vsm; private DN vsu; private DN vcm; private DN vcu; private DN vn; private DN ne; /** * Ensures that the Directory Server is running. * * @throws Exception If an unexpected problem occurs. */ @BeforeClass() public void startServer() throws Exception { TestCaseUtils.startServer(); memberType = DirectoryServer.getAttributeType("member", false); assertNotNull(memberType); uniqueMemberType = DirectoryServer.getAttributeType("uniquemember", false); assertNotNull(uniqueMemberType); groupManager = DirectoryServer.getGroupManager(); u1 = DN.decode("uid=test.1,ou=People,o=test"); u2 = DN.decode("uid=test.2,ou=People,o=test"); u3 = DN.decode("uid=test.3,ou=People,o=test"); u4 = DN.decode("uid=test.4,ou=People,o=test"); da = DN.decode("cn=Dynamic All Users,ou=Groups,o=test"); d1 = DN.decode("cn=Dynamic One User,ou=Groups,o=test"); sm = DN.decode("cn=Static member List,ou=Groups,o=test"); su = DN.decode("cn=Static uniqueMember List,ou=Groups,o=test"); vmda = DN.decode("cn=Virtual member All Users,ou=Groups,o=test"); vuda = DN.decode("cn=Virtual uniqueMember All Users,ou=Groups,o=test"); vmd1 = DN.decode("cn=Virtual member One User,ou=Groups,o=test"); vud1 = DN.decode("cn=Virtual uniqueMember One User,ou=Groups,o=test"); vsm = DN.decode("cn=Virtual Static member List,ou=Groups,o=test"); vsu = DN.decode("cn=Virtual Static uniqueMember List,ou=Groups,o=test"); vcm = DN.decode("cn=Crossover member Static Group,ou=Groups,o=test"); vcu = DN.decode("cn=Crossover uniqueMember Static Group,ou=Groups,o=test"); vn = DN.decode("cn=Virtual Nonexistent,ou=Groups,o=test"); ne = DN.decode("cn=Nonexistent,ou=Groups,o=test"); } /** * Tests creating a new instance of a virtual static group from a valid entry. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testCreateValidGroup() throws Exception { Entry entry = TestCaseUtils.makeEntry( "dn: cn=Valid Virtual Static Group,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Valid Virtual Static Group", "ds-target-group-dn: cn=Static member List,ou=Groups,o=test"); VirtualStaticGroup groupImplementation = new VirtualStaticGroup(); VirtualStaticGroup groupInstance = groupImplementation.newInstance(entry); assertNotNull(groupInstance); groupImplementation.finalizeGroupImplementation(); } /** * Retrieves a set of invalid vittual static group definition entries. * * @return A set of invalid virtul static group definition entries. * * @throws Exception If an unexpected problem occurs. */ @DataProvider(name = "invalidGroups") public Object[][] getInvalidGroupDefinitions() throws Exception { List<Entry> groupEntries = TestCaseUtils.makeEntries( "dn: cn=Not a Virtual Static Group,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "cn: Not a Virtual Static Group", "member: uid=test.1,ou=People,o=test", "", "dn: cn=No Target,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: No Target", "", "dn: cn=Invalid Target,ou=Groups,o=test", "objectClass: top", "objectClass: groupOfNames", "objectClass: ds-virtual-static-group", "cn: Invalid Target", "ds-target-group-dn: invalid"); Object[][] entryArray = new Object[groupEntries.size()][1]; for (int i=0; i < entryArray.length; i++) { entryArray[i][0] = groupEntries.get(i); } return entryArray; } /** * Tests creating a new instance of a virtual static group from an invalid * entry. * * @throws Exception If an unexpected problem occurs. */ @Test(dataProvider = "invalidGroups", expectedExceptions = { DirectoryException.class }) public void testCreateInvalidGroup(Entry entry) throws Exception { VirtualStaticGroup groupImplementation = new VirtualStaticGroup(); try { VirtualStaticGroup groupInstance = groupImplementation.newInstance(entry); } finally { groupImplementation.finalizeGroupImplementation(); } } /** * Performs general tests of the group API for virtual static groups with a * group that has a real target group. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testGroupAPI() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualStaticGroup g = (VirtualStaticGroup) groupManager.getGroupInstance(vmda); assertNotNull(g); assertTrue(g.isMember(u1)); assertNotNull(g.getGroupDefinitionFilter()); assertEquals(g.getGroupDN(), vmda); assertEquals(g.getTargetGroupDN(), da); assertFalse(g.supportsNestedGroups()); assertTrue(g.getNestedGroupDNs().isEmpty()); assertFalse(g.mayAlterMemberList()); Entry entry = DirectoryServer.getEntry(u1); assertTrue(g.isMember(entry)); MemberList memberList = g.getMembers(); assertTrue(memberList.hasMoreMembers()); assertNotNull(memberList.nextMemberDN()); assertNotNull(memberList.nextMemberEntry()); assertNotNull(memberList.nextMemberDN()); assertNotNull(memberList.nextMemberDN()); assertFalse(memberList.hasMoreMembers()); SearchFilter filter = SearchFilter.createFilterFromString("(sn=1)"); memberList = g.getMembers(DN.decode("o=test"), SearchScope.WHOLE_SUBTREE, filter); assertTrue(memberList.hasMoreMembers()); assertNotNull(memberList.nextMemberDN()); assertFalse(memberList.hasMoreMembers()); try { g.addNestedGroup(d1); fail("Expected an exception from addNestedGroupDN"); } catch (Exception e) {} try { g.removeNestedGroup(d1); fail("Expected an exception from removeNestedGroupDN"); } catch (Exception e) {} try { g.addMember(entry); fail("Expected an exception from addMember"); } catch (Exception e) {} try { g.removeMember(u1); fail("Expected an exception from removeMember"); } catch (Exception e) {} assertNotNull(g.toString()); cleanUp(); } /** * Performs general tests of the group API for virtual static groups with a * group that has a nonexistent target group. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testGroupAPINonexistent() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualStaticGroup g = (VirtualStaticGroup) groupManager.getGroupInstance(vn); assertNotNull(g); assertNotNull(g.getGroupDefinitionFilter()); assertEquals(g.getGroupDN(), vn); assertEquals(g.getTargetGroupDN(), ne); assertFalse(g.supportsNestedGroups()); assertTrue(g.getNestedGroupDNs().isEmpty()); assertFalse(g.mayAlterMemberList()); Entry entry = DirectoryServer.getEntry(u1); try { g.isMember(u1); fail("Expected an exception from isMember(DN)"); } catch (Exception e) {} try { g.isMember(entry); fail("Expected an exception from isMember(Entry)"); } catch (Exception e) {} try { g.getMembers(); fail("Expected an exception from getMembers()"); } catch (Exception e) {} try { SearchFilter filter = SearchFilter.createFilterFromString("(sn=1)"); g.getMembers(DN.decode("o=test"), SearchScope.WHOLE_SUBTREE, filter); fail("Expected an exception from getMembers(base, scope, filter)"); } catch (Exception e) {} try { g.addNestedGroup(d1); fail("Expected an exception from addNestedGroupDN"); } catch (Exception e) {} try { g.removeNestedGroup(d1); fail("Expected an exception from removeNestedGroupDN"); } catch (Exception e) {} try { g.addMember(entry); fail("Expected an exception from addMember"); } catch (Exception e) {} try { g.removeMember(u1); fail("Expected an exception from removeMember"); } catch (Exception e) {} assertNotNull(g.toString()); cleanUp(); } /** * Tests the behavior of the virtual static group with a dynamic group. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualGroupDynamicGroupWithMember() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualStaticGroup g = (VirtualStaticGroup) groupManager.getGroupInstance(vmda); assertNotNull(g); assertTrue(g.isMember(u1)); assertTrue(g.isMember(u2)); assertTrue(g.isMember(u3)); assertTrue(g.isMember(u4)); cleanUp(); } /** * Tests the behavior of the virtual static group with a static group based on * the member attribute. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualGroupStaticGroupWithMember() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualStaticGroup g = (VirtualStaticGroup) groupManager.getGroupInstance(vsm); assertNotNull(g); assertTrue(g.isMember(u1)); assertFalse(g.isMember(u2)); assertTrue(g.isMember(u3)); assertFalse(g.isMember(u4)); cleanUp(); } /** * Tests the behavior of the virtual static group with a static group based on * the uniqueMember attribute. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualGroupStaticGroupWithUniqueMember() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualStaticGroup g = (VirtualStaticGroup) groupManager.getGroupInstance(vsu); assertNotNull(g); assertFalse(g.isMember(u1)); assertTrue(g.isMember(u2)); assertTrue(g.isMember(u3)); assertFalse(g.isMember(u4)); cleanUp(); } /** * Performs general tests of the virtual attribute provider API for the member * virtual attribute with a target group that exists. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualAttributeAPI() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualAttributeRule rule = null; for (VirtualAttributeRule r : DirectoryServer.getVirtualAttributes()) { if (r.getAttributeType().equals(memberType)) { rule = r; break; } } assertNotNull(rule); MemberVirtualAttributeProvider provider = (MemberVirtualAttributeProvider) rule.getProvider(); assertNotNull(provider); Entry entry = DirectoryServer.getEntry(vsm); assertNotNull(entry); assertTrue(provider.isMultiValued()); LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule); assertNotNull(values); assertFalse(values.isEmpty()); assertTrue(provider.hasValue(entry, rule)); assertTrue(provider.hasValue(entry, rule, new AttributeValue(memberType, u1.toString()))); assertFalse(provider.hasValue(entry, rule, new AttributeValue(memberType, ne.toString()))); assertTrue(provider.hasAnyValue(entry, rule, values)); assertFalse(provider.hasAnyValue(entry, rule, Collections.<AttributeValue>emptySet())); assertEquals(provider.matchesSubstring(entry, rule, null, null, null), ConditionResult.UNDEFINED); assertEquals(provider.greaterThanOrEqualTo(entry, rule, null), ConditionResult.UNDEFINED); assertEquals(provider.lessThanOrEqualTo(entry, rule, null), ConditionResult.UNDEFINED); assertEquals(provider.approximatelyEqualTo(entry, rule, null), ConditionResult.UNDEFINED); InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = new InternalSearchOperation(conn, conn.nextOperationID(), conn.nextMessageID(), null, DN.decode("o=test"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, SearchFilter.createFilterFromString( "(member=" + u1.toString() + ")"), null, null); assertFalse(provider.isSearchable(rule, searchOperation)); provider.processSearch(rule, searchOperation); assertFalse(searchOperation.getResultCode() == ResultCode.SUCCESS); cleanUp(); } /** * Performs general tests of the virtual attribute provider API for the member * virtual attribute with a target group that does not exist. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualAttributeAPINonexistent() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); VirtualAttributeRule rule = null; for (VirtualAttributeRule r : DirectoryServer.getVirtualAttributes()) { if (r.getAttributeType().equals(memberType)) { rule = r; break; } } assertNotNull(rule); MemberVirtualAttributeProvider provider = (MemberVirtualAttributeProvider) rule.getProvider(); assertNotNull(provider); Entry entry = DirectoryServer.getEntry(vn); assertNotNull(entry); assertTrue(provider.isMultiValued()); LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule); assertNotNull(values); assertTrue(values.isEmpty()); assertFalse(provider.hasValue(entry, rule)); assertFalse(provider.hasValue(entry, rule, new AttributeValue(memberType, u1.toString()))); assertFalse(provider.hasValue(entry, rule, new AttributeValue(memberType, ne.toString()))); assertFalse(provider.hasAnyValue(entry, rule, values)); assertFalse(provider.hasAnyValue(entry, rule, Collections.<AttributeValue>emptySet())); assertEquals(provider.matchesSubstring(entry, rule, null, null, null), ConditionResult.UNDEFINED); assertEquals(provider.greaterThanOrEqualTo(entry, rule, null), ConditionResult.UNDEFINED); assertEquals(provider.lessThanOrEqualTo(entry, rule, null), ConditionResult.UNDEFINED); assertEquals(provider.approximatelyEqualTo(entry, rule, null), ConditionResult.UNDEFINED); InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = new InternalSearchOperation(conn, conn.nextOperationID(), conn.nextMessageID(), null, DN.decode("o=test"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, SearchFilter.createFilterFromString( "(member=" + u1.toString() + ")"), null, null); assertFalse(provider.isSearchable(rule, searchOperation)); provider.processSearch(rule, searchOperation); assertFalse(searchOperation.getResultCode() == ResultCode.SUCCESS); cleanUp(); } /** * Tests the behavior of the member virtual attribute with a dynamic group. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualAttrDynamicGroupWithMember() throws Exception { TestCaseUtils.initializeTestBackend(true); TestCaseUtils.addEntries(LDIF_LINES); Entry e = DirectoryServer.getEntry(vmda); assertNotNull(e); assertTrue(e.hasAttribute(memberType)); Attribute a = e.getAttribute(memberType).get(0); assertEquals(a.getValues().size(), 4); AttributeValue v = new AttributeValue(memberType, u1.toString()); assertTrue(a.hasValue(v)); cleanUp(); } /** * Tests the behavior of the member virtual attribute with a dynamic group. * The target dynamic group will initially have only one memberURL which * matches only one user, but will then be updated on the fly to contain a * second URL that matches all users. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testVirtualAttrDynamicGroupWithUpdatedMemberURLs() 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.ADD, new Attribute("memberurl", "ldap:///o=test??sub?(objectClass=person)"))); ModifyOperation modifyOperation = conn.processModify(d1, mods); assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); a = e.getAttribute(memberType).get(0); assertEquals(a.getValues().size(), 4); assertTrue(a.hasValue(v)); cleanUp(); } /** * Removes all of the groups that have been added to the server. * * @throws Exception If an unexpected problem occurs. */ private void cleanUp() throws Exception { InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation searchOperation = conn.processSearch(DN.decode("ou=Groups,dc=example,dc=com"), SearchScope.SINGLE_LEVEL, SearchFilter.createFilterFromString("(objectClass=*)")); for (Entry e : searchOperation.getSearchEntries()) { conn.processDelete(e.getDN()); } } }