/* * 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 * * * Copyright 2006-2010 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS. */ package org.opends.server.core.networkgroups; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.opends.server.config.ConfigConstants.DN_BACKEND_BASE; import java.util.ArrayList; import java.util.Collections; import static org.opends.messages.CoreMessages.*; import org.opends.server.TestCaseUtils; import org.opends.server.DirectoryServerTestCase; import org.opends.server.admin.std.meta.NetworkGroupCfgDefn.AllowedAuthMethod; import org.opends.server.api.ClientConnection; import org.opends.server.core.*; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.types.Attribute; import org.opends.server.types.Attributes; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.ByteString; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; 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.workflowelement.WorkflowElement; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * This set of tests test the network groups. */ public class NetworkGroupTest extends DirectoryServerTestCase { //=========================================================================== // // B E F O R E C L A S S // //=========================================================================== /** * Sets up the environment for performing the tests in this suite. * * @throws Exception if the environment could not be set up. */ @BeforeClass public void setUp() throws Exception { // This test suite depends on having the schema available, // so we'll start the server. TestCaseUtils.startServer(); } //=========================================================================== // // D A T A P R O V I D E R // //=========================================================================== /** * Provides information to create a network group with one workflow inside. * * Each set of DNs contains: * - one network group identifier * - one base DN for the workflow to register with the network group */ @DataProvider (name = "DNSet_0") public Object[][] initDNSet_0() throws Exception { // Network group ID String networkGroupID1 = "networkGroup1"; String networkGroupID2 = "networkGroup2"; // Workflow base DNs DN dn1 = null; DN dn2 = null; try { dn1 = DN.decode("o=test1"); dn2 = DN.decode("o=test2"); } catch (DirectoryException de) { throw de; } // Network group info Object[][] myData = { // Test1: create a network group with the identifier networkGroupID1 { networkGroupID1, dn1 }, // Test2: create the same network group to check that previous // network group was properly cleaned. { networkGroupID1, dn1 }, // Test3: create another network group { networkGroupID2, dn2 }, }; return myData; } /** * Provides a single DN to search a workflow in a network group. * * Each set of DNs is composed of: * - one baseDN * - one subordinateDN * - a boolean telling whether we expect to find a workflow for the baseDN * in the default network group * - a boolean telling whether we expect to find a workflow for the baseDN * in the administration network group * - a boolean telling whether we expect to find a workflow for the baseDN * in the internal network group * * @return set of DNs * @throws Exception when DN.decode fails */ @DataProvider(name = "DNSet_1") public Object[][] initDNSet_1() throws Exception { DN dnRootDSE = null; DN dnConfig = null; DN dnMonitor = null; DN dnSchema = null; DN dnTasks = null; DN dnBackups = null; DN dnDummy = null; DN dnSubordinateConfig = null; DN dnSubordinateMonitor = null; DN dnSubordinateTasks = null; try { dnRootDSE = DN.decode(""); dnConfig = DN.decode("cn=config"); dnMonitor = DN.decode("cn=monitor"); dnSchema = DN.decode("cn=schema"); dnTasks = DN.decode("cn=tasks"); dnBackups = DN.decode("cn=backups"); dnDummy = DN.decode("o=dummy_suffix"); dnSubordinateConfig = DN.decode("cn=Work Queue,cn=config"); dnSubordinateMonitor = DN.decode("cn=schema Backend,cn=monitor"); dnSubordinateTasks = DN.decode("cn=Scheduled Tasks,cn=tasks"); // No DN subordinate for schema because the schema backend is // currently empty. // No DN subordinate for cn=backups because by default there is no // child entry under cn=backups. } catch (DirectoryException de) { throw de; } // Sets of DNs Object[][] myData = { { dnRootDSE, null, true, true, true }, { dnConfig, dnSubordinateConfig, true, true, true }, { dnMonitor, dnSubordinateMonitor, true, true, true }, { dnTasks, dnSubordinateTasks, true, true, true }, { dnSchema, null, true, true, true }, { dnBackups, null, true, true, true }, { dnDummy, null, false, false, false }, }; return myData; } /** * Provides information to create a network group to test the routing * process. * * Each set of DNs contains: * - one base DN for the 1st workflow * - one base DN for the 2nd workflow * - one base DN for the 3rd workflow * - one subordinate DN for the 1st workflow * - one subordinate DN for the 2nd workflow * - one subordinate DN for the 3rd workflow * - one unrelated DN which has no hierarchical relationship with * any of the above DNs */ @DataProvider (name = "DNSet_2") public Object[][] initDNSet_2() throws Exception { // Network group definition DN dn1 = null; DN dn2 = null; DN dn3 = null; DN subordinate1 = null; DN subordinate2 = null; DN subordinate3 = null; DN unrelatedDN = null; try { dn1 = DN.decode("o=test1"); dn2 = DN.decode("o=test2"); dn3 = DN.decode("o=test3"); subordinate1 = DN.decode("ou=subtest1,o=test1"); subordinate2 = DN.decode("ou=subtest2,o=test2"); subordinate3 = DN.decode("ou=subtest3,o=test3"); unrelatedDN = DN.decode("o=dummy"); } catch (DirectoryException de) { throw de; } // Network group info Object[][] myData = { // Test1: one DN for one workflow { dn1, null, null, subordinate1, null, null, unrelatedDN }, // Test2: two DNs for two workflows { dn1, dn2, null, subordinate1, subordinate2, null, unrelatedDN }, // Test3: three DNs for three workflows { dn1, dn2, dn3, subordinate1, subordinate2, subordinate3, unrelatedDN } }; return myData; } /** * Provides information to create a network group with resource limits. */ @DataProvider (name = "DNSet_3") public Object[][] initDNSet_3() throws Exception { // Network group definition String networkGroupID = "networkGroup1"; DN dn = null; int prio = 1; // Resource limits int maxConnections = 10; int maxConnectionsFromSameClient = 5; int maxOpsPerConn = 4; int maxConcurrentOpsPerConn = 2; int searchTimeLimit = 100; int searchSizeLimit = 50; int minSubstringLength = 4; try { dn = DN.decode("o=test1"); } catch (DirectoryException de) { throw de; } // Network group info Object[][] myData = { // Test1: one DN for one workflow { networkGroupID, dn, prio, maxConnections, maxConnectionsFromSameClient, maxOpsPerConn, maxConcurrentOpsPerConn, searchTimeLimit, searchSizeLimit, minSubstringLength } }; return myData; } /** * Provides information to create 2 network groups with different priorities. */ @DataProvider (name = "DNSet_4") public Object[][] initDNSet_4() throws Exception { String networkGroupID1 = "group1"; String networkGroupID2 = "group2"; DN dn1 = null; DN dn2 = null; try { dn1 = DN.decode("o=test1"); dn2 = DN.decode("o=test2"); } catch (DirectoryException de) { throw de; } Object[][] myData = { { networkGroupID1, dn1, 1, networkGroupID2, dn2, 2 }, { networkGroupID1, dn1, 2, networkGroupID2, dn2, 1 } }; return myData; } /** * Provides the priorities for 3 network groups */ @DataProvider (name = "PrioritySet_0") public Object[][] initPrioritySet_0() { Object[][] myData = { { 1, 2, 3 }, { 1, 3, 2 }, { 2, 1, 3 }, { 2, 3, 1 }, { 3, 1, 2 }, { 3, 2, 1 } }; return myData; } /** * Provides a bind DN filter to build network group criteria * and the expected result (true if the connection with * cn=Directory Manager, cn =Root DNs, cn=config should match the * network group, false if it should go into the default network group). */ @DataProvider (name = "BindFilterSet_0") public Object[][] initBindFilterSet_0() { Object[][] myData = { { "*, cn=Root DNs, cn=config", true }, { "cn=Dir*, cn=Root DNs, cn=config", true }, { "cn=*", false }, { "uid=*", false }, { "**, cn=config", true }, { "*, cn=config", false } }; return myData; } //=========================================================================== // // T E S T C A S E S // //=========================================================================== /** * Tests the network group registration. * * @param networkGroupID the ID of the network group to register * @param workflowBaseDN1 the base DN of the first workflow node to register * in the network group */ @Test (dataProvider = "DNSet_0", groups = "virtual") public void testNetworkGroupRegistration( String networkGroupID, DN workflowBaseDN ) throws Exception { // Create and register the network group with the server. NetworkGroup networkGroup = new NetworkGroup(networkGroupID); networkGroup.register(); // Register again the network group with the server and catch the // expected DirectoryServer exception. boolean exceptionRaised = false; try { networkGroup.register(); } catch (InitializationException e) { exceptionRaised = true; assertEquals(e.getMessageObject().getDescriptor(), ERR_REGISTER_NETWORK_GROUP_ALREADY_EXISTS); } assertEquals(exceptionRaised, true); // Create a workflow -- the workflow ID is the string representation // of the workflow base DN. WorkflowElement<?> nullWE = null; WorkflowImpl workflow = new WorkflowImpl( workflowBaseDN.toString(), workflowBaseDN, null, nullWE); // Register the workflow with the network group. networkGroup.registerWorkflow(workflow); // Register again the workflow with the network group and catch the // expected DirectoryServer exception. exceptionRaised = false; try { networkGroup.registerWorkflow(workflow); } catch (DirectoryException de) { exceptionRaised = true; assertEquals( de.getMessageObject().getDescriptor(), ERR_REGISTER_WORKFLOW_NODE_ALREADY_EXISTS); } assertEquals(exceptionRaised, true); // Clean the network group networkGroup.deregisterWorkflow(workflow.getWorkflowId()); networkGroup.deregister(); } /** * Check the route process in the default network group. * * @param dnToSearch the DN of a workflow to search in the default * network group * @param dnSubordinate a subordinate DN of dnToSearch * @param exists true if we are supposed to find a workflow for * dnToSearch */ @Test (dataProvider = "DNSet_1", groups = "virtual") public void checkDefaultNetworkGroup( DN dnToSearch, DN dnSubordinate, boolean existsInDefault, boolean existsInAdmin, boolean existsInInternal ) { // let's get the default network group -- it should always exist NetworkGroup defaultNG = NetworkGroup.getDefaultNetworkGroup(); assertNotNull(defaultNG); // let's check the routing through the network group doCheckNetworkGroup(defaultNG, dnToSearch, dnSubordinate, null, existsInDefault); // Dump the default network group dump(defaultNG, "defaultNetworkGroup> "); // let's get the admin network group -- it should always exist NetworkGroup adminNG = NetworkGroup.getAdminNetworkGroup(); assertNotNull(adminNG); // let's check the routing through the network group doCheckNetworkGroup(adminNG, dnToSearch, dnSubordinate, null, existsInAdmin); // Dump the default network group dump(adminNG, "adminNetworkGroup> "); // let's get the internal network group -- it should always exist NetworkGroup internalNG = NetworkGroup.getInternalNetworkGroup(); assertNotNull(internalNG); // let's check the routing through the network group doCheckNetworkGroup(internalNG, dnToSearch, dnSubordinate, null, existsInInternal); // Dump the default network group dump(internalNG, "internalNetworkGroup> "); } /** * Creates a network group with several workflows inside and do some check * on the route processing. * * @param dn1 the DN for the 1st workflow * @param dn2 the DN for the 2nd workflow * @param dn3 the DN for the 3rd workflow * @param subordinate1 the subordinate DN for the 1st workflow * @param subordinate2 the subordinate DN for the 2nd workflow * @param subordinate3 the subordinate DN for the 3rd workflow * @param unrelatedDN a DN with no hierarchical relationship with * any of the DNs above * * @throws DirectoryException If the network group ID for a provided * network group conflicts with the network * group ID of an existing network group. */ @Test (dataProvider = "DNSet_2", groups = "virtual") public void createNetworkGroup( DN dn1, DN dn2, DN dn3, DN subordinate1, DN subordinate2, DN subordinate3, DN unrelatedDN ) throws Exception { // The network group identifier is always the same for this test. String networkGroupID = "Network Group for test2"; // Create the network group NetworkGroup networkGroup = new NetworkGroup(networkGroupID); assertNotNull(networkGroup); // Register the network group with the server networkGroup.register(); // Create and register workflow 1, 2 and 3 createAndRegisterWorkflow(networkGroup, dn1); createAndRegisterWorkflow(networkGroup, dn2); createAndRegisterWorkflow(networkGroup, dn3); // Check the route through the network group doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, true); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, true); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, true); // Deregister the workflow1 and check the route again. // Workflow to deregister is identified by its baseDN. networkGroup.deregisterWorkflow(dn1); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, true); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, true); // Deregister the workflow2 and check the route again networkGroup.deregisterWorkflow(dn2); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, true); // Deregister the workflow3 and check the route again networkGroup.deregisterWorkflow(dn3); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, false); // Now create again the workflow 1, 2 and 3... WorkflowImpl w1; WorkflowImpl w2; WorkflowImpl w3; w1 = createAndRegisterWorkflow(networkGroup, dn1); w2 = createAndRegisterWorkflow(networkGroup, dn2); w3 = createAndRegisterWorkflow(networkGroup, dn3); // ... and deregister the workflows using their workflowID // instead of their baseDN if (w1 != null) { networkGroup.deregisterWorkflow(w1.getWorkflowId()); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, true); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, true); } if (w2 != null) { networkGroup.deregisterWorkflow(w2.getWorkflowId()); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, true); } if (w3 != null) { networkGroup.deregisterWorkflow(w3.getWorkflowId()); doCheckNetworkGroup(networkGroup, dn1, subordinate1, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn2, subordinate2, unrelatedDN, false); doCheckNetworkGroup(networkGroup, dn3, subordinate3, unrelatedDN, false); } // Deregister the network group networkGroup.deregister(); } /** * This test checks that network groups are updated as appropriate when * backend base DNs are added or removed. When a new backend base DN is * added, the new suffix should be accessible for the route process - ie. * a workflow should be created and be a potential candidate for the route * process. Similarly, when a backend base DN is removed its associated * workflow should be removed; subsequently, any request targeting the * removed suffix should be rejected and a no such entry status code be * returned. */ @Test public void testBackendBaseDNModification() throws Exception { String suffix = "dc=example,dc=com"; String suffix2 = "o=networkgroup suffix"; String backendBaseDNName = "ds-cfg-base-dn"; // Initialize a backend with a base entry. TestCaseUtils.clearJEBackend(true, "userRoot", suffix); // Create a client connection for the test. InternalClientConnection connection = InternalClientConnection.getRootConnection(); // Check that suffix is accessible while suffix2 is not. searchEntry(connection, suffix, true); searchEntry(connection, suffix2, false); // Add a new suffix in the backend and create a base entry for the // new suffix. String backendConfigDN = "ds-cfg-backend-id=userRoot," + DN_BACKEND_BASE; modifyAttribute( connection, backendConfigDN, ModificationType.ADD, backendBaseDNName, suffix2); addBaseEntry(connection, suffix2, "networkgroup suffix"); // Both old and new suffix should be accessible. searchEntry(connection, suffix, true); searchEntry(connection, suffix2, true); // Remove the new suffix... modifyAttribute( connection, backendConfigDN, ModificationType.DELETE, backendBaseDNName, suffix2); // ...and check that the removed suffix is no more accessible. searchEntry(connection, suffix, true); searchEntry(connection, suffix2, false); // Replace the suffix with suffix2 in the backend modifyAttribute( connection, backendConfigDN, ModificationType.REPLACE, backendBaseDNName, suffix2); // Now none of the suffixes are accessible: this means the entries // under the old suffix are not moved to the new suffix. searchEntry(connection, suffix, false); searchEntry(connection, suffix2, false); // Add a base entry for the new suffix addBaseEntry(connection, suffix2, "networkgroup suffix"); // The new suffix is accessible while the old one is not. searchEntry(connection, suffix, false); searchEntry(connection, suffix2, true); // Reset the configuration with previous suffix modifyAttribute( connection, backendConfigDN, ModificationType.REPLACE, backendBaseDNName, suffix); } /** * Tests that routing mode changes cause the network group config * manager to be initialized, shutdown, and reinitialized correctly. * <p> * Disabled because NGs are not supported (issue OPENDJ-335). * * @see <a * href="https://opends.dev.java.net/issues/show_bug.cgi?id=3775">Issue 3775</a> * @throws Exception * If an unexpected error occurred. */ @Test(enabled=false) public void testIssue3775() throws Exception { // Switch to and from manual mode twice in order to ensure that the // config manager is initialized twice. Then register a network // group. If the initialization has worked properly the network // group should be added successfully. In the case of issue 3775, // the config add listeners ended up being added twice so adding a // network group failed because the admin framework thought it had // been added twice. // Switch to manual mode once. TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:manual"); try { // Switch back. TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:auto"); // Switch to manual mode twice. TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:manual"); // Now add network group. final String networkGroupID = "Network group issue 3775"; TestCaseUtils.dsconfig( "create-network-group", "--group-name", networkGroupID, "--set", "enabled:true", "--set", "priority:" + 123); try { // Ensure that the network group was created ok. NetworkGroup networkGroup = NetworkGroup.getNetworkGroup(networkGroupID); assertNotNull(networkGroup, "The network group does not seem to be registered."); } finally { // Remove the network group. TestCaseUtils.dsconfig( "delete-network-group", "--group-name", networkGroupID); } } finally { TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:auto"); } } /** * Tests the network group resource limits * <p> * Disabled because NGs are not supported (issue OPENDJ-335). * * @param networkGroupID the ID of the network group to register * @param workflowBaseDN1 the base DN of the first workflow node to register * in the network group */ @Test (dataProvider = "DNSet_3", groups = "virtual", enabled=false) public void testNetworkGroupResourceLimits( String networkGroupID, DN workflowBaseDN, int priority, final int maxConnections, final int maxConnectionsFromSameClient, final int maxOpsPerConn, final int maxConcurrentOpsPerConn, final int searchTimeLimit, final int searchSizeLimit, final int minSubstringLength ) throws Exception { // Create and register the network group with the server. TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:manual"); try { TestCaseUtils.dsconfig( "create-network-group", "--group-name", networkGroupID, "--set", "enabled:true", "--set", "priority:" + priority); try { // Ensure that the network group was created ok. NetworkGroup networkGroup = NetworkGroup.getNetworkGroup(networkGroupID); assertNotNull(networkGroup, "The network group does not seem to be registered."); TestCaseUtils.dsconfig( "create-network-group-qos-policy", "--group-name", networkGroupID, "--type", "resource-limits", "--set", "max-concurrent-ops-per-connection:" + maxConcurrentOpsPerConn, "--set", "max-connections:" + maxConnections, "--set", "max-connections-from-same-ip:" + maxConnectionsFromSameClient, "--set", "max-ops-per-connection:" + maxOpsPerConn, "--set", "min-substring-length:" + minSubstringLength, "--set", "size-limit:" + searchSizeLimit, "--set", "time-limit:" + searchTimeLimit + "s"); // Check that the policy was created. ResourceLimitsPolicy policy = networkGroup.getNetworkGroupQOSPolicy(ResourceLimitsPolicy.class); assertNotNull(policy, "The policy was not registered."); // Check the resource limits are set properly. assertEquals(policy.getTimeLimit(), searchTimeLimit); assertEquals(policy.getSizeLimit(), searchSizeLimit); assertEquals(policy.getMinSubstring(), minSubstringLength); assertEquals(networkGroup.getTimeLimit(), searchTimeLimit); assertEquals(networkGroup.getSizeLimit(), searchSizeLimit); assertEquals(networkGroup.getMinSubstring(), minSubstringLength); TestCaseUtils.dsconfig( "delete-network-group-qos-policy", "--group-name", networkGroupID, "--policy-type", "resource-limits"); // Check that the policy was removed. policy = networkGroup.getNetworkGroupQOSPolicy(ResourceLimitsPolicy.class); assertNull(policy, "The policy was not deregistered."); } finally { // The policy will get removed by this as well. TestCaseUtils.dsconfig("delete-network-group", "--group-name", networkGroupID); } } finally { TestCaseUtils.dsconfig( "set-global-configuration-prop", "--set", "workflow-configuration-mode:auto"); } } /** * Tests the mechanism to attribute a network group to a client connection, * comparing the priority. */ @Test (dataProvider = "DNSet_4", groups = "virtual") public void testNetworkGroupPriority( String ng1, DN dn1, int prio1, String ng2, DN dn2, int prio2 ) throws Exception { // Create and register the network group with the server. NetworkGroup networkGroup1 = new NetworkGroup(ng1); networkGroup1.register(); networkGroup1.setNetworkGroupPriority(prio1); NetworkGroup networkGroup2 = new NetworkGroup(ng2); networkGroup2.register(); networkGroup2.setNetworkGroupPriority(prio2); // Create a workflow -- the workflow ID is the string representation // of the workflow base DN. WorkflowElement<?> nullWE = null; WorkflowImpl workflow1 = new WorkflowImpl( dn1.toString(), dn1, null, nullWE); WorkflowImpl workflow2 = new WorkflowImpl( dn2.toString(), dn2, null, nullWE); // Register the workflow with the network group. networkGroup1.registerWorkflow(workflow1); networkGroup2.registerWorkflow(workflow2); // Create a new ClientConnection ClientConnection connection = new InternalClientConnection(DN.NULL_DN); // Find a networkGroup for this connection // As the network groups define no criteria, the highest priority // must be chosen NetworkGroup ng = NetworkGroup.findMatchingNetworkGroup(connection); if (prio1 < prio2) { assertEquals(ng, networkGroup1); } else { assertEquals(ng, networkGroup2); } // Clean the network group networkGroup1.deregisterWorkflow(workflow1.getWorkflowId()); networkGroup1.deregister(); networkGroup2.deregisterWorkflow(workflow2.getWorkflowId()); networkGroup2.deregister(); } /** * Tests the mechanism to attribute a network group to a client connection, * based on the authentication method. */ @Test (dataProvider = "PrioritySet_0", groups = "virtual") public void testNetworkGroupAuthenticationMethodCriteria( int prio1, int prio2, int prio3) throws Exception { // Create a AuthMethodCriteria for anonymous connections AuthMethodConnectionCriteria authCriteria1 = new AuthMethodConnectionCriteria(Collections .singleton(AllowedAuthMethod.ANONYMOUS)); // Create a AuthMethodCriteria for simple bind connections AuthMethodConnectionCriteria authCriteria2 = new AuthMethodConnectionCriteria(Collections .singleton(AllowedAuthMethod.SIMPLE)); // Create a AuthMethodCriteria for sasl connections AuthMethodConnectionCriteria authCriteria3 = new AuthMethodConnectionCriteria(Collections .singleton(AllowedAuthMethod.SASL)); // Create and register the network group with the server. NetworkGroup networkGroup1 = new NetworkGroup("anonymous_group"); networkGroup1.register(); networkGroup1.setConnectionCriteria(authCriteria1); networkGroup1.setNetworkGroupPriority(prio1); NetworkGroup networkGroup2 = new NetworkGroup("simplebind_group"); networkGroup2.register(); networkGroup2.setConnectionCriteria(authCriteria2); networkGroup2.setNetworkGroupPriority(prio2); NetworkGroup networkGroup3 = new NetworkGroup("sasl_group"); networkGroup3.register(); networkGroup3.setConnectionCriteria(authCriteria3); networkGroup3.setNetworkGroupPriority(prio3); // Create a new client connection, with anonymous authentication ClientConnection connection1 = new InternalClientConnection(DN.NULL_DN); NetworkGroup ng = NetworkGroup.findMatchingNetworkGroup(connection1); assertEquals(ng, networkGroup1); // Use simple bind on this connection Entry userEntry = DirectoryServer.getEntry( DN.decode("cn=Directory Manager, cn=Root DNs, cn=config")); ByteString password = ByteString.valueOf("password"); ClientConnection connection2 = new InternalClientConnection( new AuthenticationInfo(userEntry, userEntry.getDN(), password, true)); ng = NetworkGroup.findMatchingNetworkGroup(connection2); assertEquals(ng, networkGroup2); // Use SASL on this connection ClientConnection connection3 = new InternalClientConnection( new AuthenticationInfo(userEntry, "external", ByteString.valueOf( "cn=Directory Manager, cn=Root DNs, cn=config"), true)); ng = NetworkGroup.findMatchingNetworkGroup(connection3); assertEquals(ng, networkGroup3); // Clean the network group networkGroup1.deregister(); networkGroup2.deregister(); networkGroup3.deregister(); } /** * Tests the mechanism to attribute a network group to a client connection, * based on the bind dn filter. */ @Test (dataProvider = "BindFilterSet_0", groups = "virtual") public void testNetworkGroupBindDnCriteria( String bindDnFilter, boolean match) throws Exception { // Create a BindDnFilterCriteria BindDNConnectionCriteria bindCriteria = BindDNConnectionCriteria.decode(Collections .singleton(bindDnFilter)); // Create and register the network group with the server. NetworkGroup networkGroup = new NetworkGroup("bindfilter_group"); networkGroup.register(); networkGroup.setConnectionCriteria(bindCriteria); NetworkGroup defaultNg = NetworkGroup.getDefaultNetworkGroup(); // Create a new client connection, with anonymous authentication // It should match the default network group // as it has no bind information ClientConnection connection1 = new InternalClientConnection(DN.NULL_DN); NetworkGroup ng = NetworkGroup.findMatchingNetworkGroup(connection1); assertEquals(ng, defaultNg); // Use simple bind on this connection Entry userEntry = DirectoryServer.getEntry( DN.decode("cn=Directory Manager, cn=Root DNs, cn=config")); ByteString password = ByteString.valueOf("password"); ClientConnection connection2 = new InternalClientConnection( new AuthenticationInfo(userEntry, userEntry.getDN(), password, true)); ng = NetworkGroup.findMatchingNetworkGroup(connection2); if (match) { assertEquals(ng, networkGroup); } else { assertEquals(ng, defaultNg); } // Use SASL on this connection ClientConnection connection3 = new InternalClientConnection( new AuthenticationInfo(userEntry, "external", ByteString.valueOf( "cn=Directory Manager, cn=Root DNs, cn=config"), true)); ng = NetworkGroup.findMatchingNetworkGroup(connection3); if (match) { assertEquals(ng, networkGroup); } else { assertEquals(ng, defaultNg); } // Clean the network group networkGroup.deregister(); } /** * Tests the mechanism to attribute a network group to a client connection, * based on the bind dn filter. */ @Test (groups = "virtual") public void testNetworkGroupSecurityCriteria() throws Exception { // Create a SecurityCriteria SecurityConnectionCriteria secCriteria = SecurityConnectionCriteria.SECURITY_REQUIRED; // Create and register the network group with the server. NetworkGroup networkGroup = new NetworkGroup("secured_group"); networkGroup.register(); networkGroup.setConnectionCriteria(secCriteria); NetworkGroup defaultNg = NetworkGroup.getDefaultNetworkGroup(); // Create a new client connection, with anonymous authentication // It should match the secured group as internal connections // are secured ClientConnection connection1 = new InternalClientConnection(DN.NULL_DN); NetworkGroup ng = NetworkGroup.findMatchingNetworkGroup(connection1); assertEquals(ng, networkGroup); // now change the criteria (security not mandatory) secCriteria = SecurityConnectionCriteria.SECURITY_NOT_REQUIRED; networkGroup.setConnectionCriteria(secCriteria); // connection1 should match the networkGroup, even though it is not // secured ng = NetworkGroup.findMatchingNetworkGroup(connection1); assertEquals(ng, networkGroup); // Clean the network group networkGroup.deregister(); } /** * This test checks that the network group takes into account the * subordinate naming context defined in the RootDSEBackend. */ @Test public void testRootDseSubordinateNamingContext() throws Exception { // Backends for the test String backend1 = "o=test-rootDSE-subordinate-naming-context-1"; String backend2 = "o=test-rootDSE-subordinate-naming-context-2"; String backendID1 = "test-rootDSE-subordinate-naming-context-1"; String backendID2 = "test-rootDSE-subordinate-naming-context-2"; // Clean all the backends. TestCaseUtils.clearDataBackends(); // Create a client connection for the test. InternalClientConnection connection = InternalClientConnection.getRootConnection(); // At this point, the list of subordinate naming context is not defined // yet (null): any public backend should be visible. Create a backend // with a base entry and check that the test naming context is visible. TestCaseUtils.initializeMemoryBackend(backendID1, backend1, true); searchPublicNamingContexts(connection, true, 1); // Create another test backend and check that the new backend is visible TestCaseUtils.initializeMemoryBackend(backendID2, backend2, true); searchPublicNamingContexts(connection, true, 2); // Now put in the list of subordinate naming context the backend1 // naming context. This white list will prevent the backend2 to be // visible. TestCaseUtils.dsconfig( "set-root-dse-backend-prop", "--set", "subordinate-base-dn:" + backend1); searchPublicNamingContexts(connection, true, 1); // === Cleaning // Reset the subordinate naming context list. // Both naming context should be visible again. TestCaseUtils.dsconfig( "set-root-dse-backend-prop", "--reset", "subordinate-base-dn"); searchPublicNamingContexts(connection, true, 2); // Clean the test backends. There is no more naming context. TestCaseUtils.clearMemoryBackend(backendID1); TestCaseUtils.clearMemoryBackend(backendID2); searchPublicNamingContexts(connection, false, 0); } /** * Searches the list of naming contexts. * * @param connection the connection to use for the search request * @param shouldExist indicates whether at least one NC should be found * @param expectedNamingContexts the number of expected naming contexts */ private void searchPublicNamingContexts( InternalClientConnection connection, boolean shouldExist, int expectedNamingContexts ) throws Exception { SearchOperation search = connection.processSearch( DN.decode(""), SearchScope.SINGLE_LEVEL, LDAPFilter.decode("(objectClass=*)").toSearchFilter()); // Check the number of found naming context ResultCode expectedRC = (shouldExist ? ResultCode.SUCCESS : ResultCode.NO_SUCH_OBJECT); assertEquals(search.getResultCode(), expectedRC); if (shouldExist) { assertEquals(search.getEntriesSent(), expectedNamingContexts); } } /** * Searches an entry on a given connection. * * @param connection the connection to use for the search request * @param baseDN the request base DN string * @param shouldExist if true the searched entry is expected to be found */ private void searchEntry( InternalClientConnection connection, String baseDN, boolean shouldExist ) throws Exception { SearchOperation search = connection.processSearch( DN.decode(baseDN), SearchScope.BASE_OBJECT, LDAPFilter.decode("(objectClass=*)").toSearchFilter()); // Compare the result code with the expected one ResultCode resultCode = search.getResultCode(); if (shouldExist) { assertEquals(resultCode, ResultCode.SUCCESS); } else { assertEquals(resultCode, ResultCode.NO_SUCH_OBJECT); } } /** * Creates a base entry for the given suffix. * * @param connection the connection to use for the add request * @param suffix the suffix for which the base entry is to be created */ private void addBaseEntry( InternalClientConnection connection, String suffix, String namingAttribute ) throws Exception { Entry e = TestCaseUtils.makeEntry( "dn: " + suffix, "objectClass: top", "objectClass: organization", "o: " + namingAttribute); AddOperation addOperation = connection.processAdd( e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); } /** * Adds/Deletes/Replaces an attribute in a given entry. * * @param connection the connection to use for the modify request * @param baseDN the request base DN string * @param modType the modification type (add/delete/replace) * @param attributeName the name of the attribute to add/delete/replace * @param attributeValue the value of the attribute to add/delete/replace */ private void modifyAttribute( InternalClientConnection connection, String baseDN, ModificationType modType, String attributeName, String attributeValue ) throws Exception { ArrayList<Modification> mods = new ArrayList<Modification>(); Attribute attributeToModify = Attributes.create(attributeName, attributeValue); mods.add(new Modification(modType, attributeToModify)); ModifyOperation modifyOperation = connection.processModify( DN.decode(baseDN), mods); assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); } /** * Checks the DN routing through a network group. * * @param networkGroup the network group to use for the check * @param dnToSearch the DN of a workflow in the network group; may * be null * @param dnSubordinate a subordinate of dnToSearch * @param unrelatedDN a DN with no hierarchical relationship with * any of the DNs above, may be null * @param shouldExist true if we are supposed to find a workflow for * dnToSearch */ private void doCheckNetworkGroup( NetworkGroup networkGroup, DN dnToSearch, DN dnSubordinate, DN unrelatedDN, boolean shouldExist ) { if (dnToSearch == null) { return; } // Let's retrieve the workflow that maps best the dnToSearch Workflow workflow = networkGroup.getWorkflowCandidate(dnToSearch); if (shouldExist) { assertNotNull(workflow); } else { assertNull(workflow); } // let's retrieve the workflow that handles the DN subordinate: // it should be the same than the one for dnToSearch if (dnSubordinate != null) { Workflow workflow2 = networkGroup.getWorkflowCandidate(dnSubordinate); assertEquals(workflow2, workflow); } // Check that the unrelatedDN is not handled by any workflow if (unrelatedDN != null) { Workflow unrelatedWorkflow = networkGroup.getWorkflowCandidate(unrelatedDN); assertNull(unrelatedWorkflow); } } /** * Creates a workflow and register it with a network group. * * @param networkGroup a network group to register the workflow with * @param workflowBaseDN the base DN of the workflow to register; may be * null * @throws DirectoryException If the workflow ID for the provided * workflow conflicts with the workflow * ID of an existing workflow. */ private WorkflowImpl createAndRegisterWorkflow( NetworkGroup networkGroup, DN workflowBaseDN ) throws DirectoryException { assertNotNull(networkGroup); if (workflowBaseDN == null) { return null; } // Create a workflow with no task inside. The workflow identifier // is the a string representation of the workflow base DN. WorkflowElement<?> rootWE = null; String workflowId = workflowBaseDN.toString(); WorkflowImpl workflow = new WorkflowImpl( workflowId, workflowBaseDN, null, rootWE); assertNotNull(workflow); // Register the workflow with the network group. networkGroup.registerWorkflow(workflow); return workflow; } /** * Prints a text to System.out. */ private void write(String msg) { System.out.print(msg); } /** * Prints a text to System.out. */ private void writeln(String msg) { write(msg + "\n"); } /** * Dump the network group info to the console. */ private void dump(NetworkGroup networkGroup, String prompt) { final boolean doDump = false; if (doDump) { StringBuilder sb = networkGroup.toString(prompt); writeln(sb.toString()); } } }