From 55053284a91de860a4189f5d169efb856ee82ce0 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 12 Sep 2011 16:00:46 +0000
Subject: [PATCH] Issue OPENDJ-262: Implement pass through authentication (PTA)

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java |  139 +++++++++++++++++++++++++++++++++++++++++++++-
 opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java                          |    2 
 2 files changed, 136 insertions(+), 5 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
index d02d685..dbd18eb 100644
--- a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
+++ b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
@@ -1279,7 +1279,7 @@
         // There's a potential, but benign, race condition here: other threads
         // could jump in and rotate through the list before we return the
         // connection factory.
-        return newNextIndex;
+        return oldNextIndex;
       }
 
     }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
index 6766d55..a41f31c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
@@ -284,8 +284,6 @@
     {
       builder.append("GetLDAPConnectionFactoryEvent(");
       builder.append(hostPort);
-      builder.append(", ");
-      builder.append(options);
       builder.append(')');
       return builder;
     }
@@ -2839,9 +2837,142 @@
 
 
 
-  // TODO: connection pooling
-  // TODO: load balancing
   // TODO: fail-over
+  // TODO: retry search/bind on error
+  // TODO: detect when servers come back online
+
+  /**
+   * Tests load balancing across 3 servers.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLoadBalancing() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg()
+        .withPrimaryServer(phost1).withPrimaryServer(phost2)
+        .withPrimaryServer(phost3)
+        .withMappingPolicy(MappingPolicy.MAPPED_SEARCH)
+        .withMappedAttribute("uid").withBaseDN("o=ad");
+
+    // Create all the events.
+    final MockProvider provider = new MockProvider();
+
+    // First of all the connection factories are created.
+    final GetLDAPConnectionFactoryEvent fe1 = new GetLDAPConnectionFactoryEvent(
+        phost1, cfg);
+    final GetLDAPConnectionFactoryEvent fe2 = new GetLDAPConnectionFactoryEvent(
+        phost2, cfg);
+    final GetLDAPConnectionFactoryEvent fe3 = new GetLDAPConnectionFactoryEvent(
+        phost3, cfg);
+    provider.expectEvent(fe1).expectEvent(fe2).expectEvent(fe3);
+
+    // Get connection for phost1, then search, then bind.
+    final GetConnectionEvent ceSearch1 = new GetConnectionEvent(fe1);
+    final GetConnectionEvent ceBind1 = new GetConnectionEvent(fe1);
+    provider
+        .expectEvent(ceSearch1)
+        .expectEvent(
+            new SimpleBindEvent(ceSearch1, searchBindDNString,
+                "searchPassword", ResultCode.SUCCESS))
+        .expectEvent(
+            new SearchEvent(ceSearch1, "o=ad", SearchScope.WHOLE_SUBTREE,
+                "(uid=aduser)", adDNString))
+        .expectEvent(ceBind1)
+        .expectEvent(
+            new SimpleBindEvent(ceBind1, adDNString, userPassword,
+                ResultCode.SUCCESS));
+
+    // Get connection for phost2, then search, then bind.
+    final GetConnectionEvent ceSearch2 = new GetConnectionEvent(fe2);
+    final GetConnectionEvent ceBind2 = new GetConnectionEvent(fe2);
+    provider
+        .expectEvent(ceSearch2)
+        .expectEvent(
+            new SimpleBindEvent(ceSearch2, searchBindDNString,
+                "searchPassword", ResultCode.SUCCESS))
+        .expectEvent(
+            new SearchEvent(ceSearch2, "o=ad", SearchScope.WHOLE_SUBTREE,
+                "(uid=aduser)", adDNString))
+        .expectEvent(ceBind2)
+        .expectEvent(
+            new SimpleBindEvent(ceBind2, adDNString, userPassword,
+                ResultCode.SUCCESS));
+
+    // Get connection for phost3, then search, then bind.
+    final GetConnectionEvent ceSearch3 = new GetConnectionEvent(fe3);
+    final GetConnectionEvent ceBind3 = new GetConnectionEvent(fe3);
+    provider
+        .expectEvent(ceSearch3)
+        .expectEvent(
+            new SimpleBindEvent(ceSearch3, searchBindDNString,
+                "searchPassword", ResultCode.SUCCESS))
+        .expectEvent(
+            new SearchEvent(ceSearch3, "o=ad", SearchScope.WHOLE_SUBTREE,
+                "(uid=aduser)", adDNString))
+        .expectEvent(ceBind3)
+        .expectEvent(
+            new SimpleBindEvent(ceBind3, adDNString, userPassword,
+                ResultCode.SUCCESS));
+
+    // Repeat again using cached connection to phost1: search, then bind.
+    provider.expectEvent(
+        new SearchEvent(ceSearch1, "o=ad", SearchScope.WHOLE_SUBTREE,
+            "(uid=aduser)", adDNString)).expectEvent(
+        new SimpleBindEvent(ceBind1, adDNString, userPassword,
+            ResultCode.SUCCESS));
+
+    // Repeat again using cached connection to phost2: search, then bind.
+    provider.expectEvent(
+        new SearchEvent(ceSearch2, "o=ad", SearchScope.WHOLE_SUBTREE,
+            "(uid=aduser)", adDNString)).expectEvent(
+        new SimpleBindEvent(ceBind2, adDNString, userPassword,
+            ResultCode.SUCCESS));
+
+    // Repeat again using cached connection to phost3: search, then bind.
+    provider.expectEvent(
+        new SearchEvent(ceSearch3, "o=ad", SearchScope.WHOLE_SUBTREE,
+            "(uid=aduser)", adDNString)).expectEvent(
+        new SimpleBindEvent(ceBind3, adDNString, userPassword,
+            ResultCode.SUCCESS));
+
+    // Connections should be cached until the policy is finalized.
+
+    // Obtain policy and state.
+    final LDAPPassThroughAuthenticationPolicyFactory factory = new LDAPPassThroughAuthenticationPolicyFactory(
+        provider);
+    assertTrue(factory.isConfigurationAcceptable(cfg, null));
+    final AuthenticationPolicy policy = factory.createAuthenticationPolicy(cfg);
+
+    // Cycle twice through the LB pool.
+    for (int i = 0; i < 6; i++)
+    {
+      final AuthenticationPolicyState state = policy
+          .createAuthenticationPolicyState(userEntry);
+      assertEquals(state.getAuthenticationPolicy(), policy);
+
+      // Perform authentication.
+      assertTrue(state.passwordMatches(ByteString.valueOf(userPassword)));
+
+      state.finalizeStateAfterBind();
+    }
+
+    // Cached connections should be closed when the policy is finalized.
+    provider.expectEvent(new CloseEvent(ceSearch1));
+    provider.expectEvent(new CloseEvent(ceSearch2));
+    provider.expectEvent(new CloseEvent(ceSearch3));
+    provider.expectEvent(new CloseEvent(ceBind1));
+    provider.expectEvent(new CloseEvent(ceBind2));
+    provider.expectEvent(new CloseEvent(ceBind3));
+
+    // Tear down and check final state.
+    policy.finalizeAuthenticationPolicy();
+    provider.assertAllExpectedEventsReceived();
+  }
+
+
 
   MockPolicyCfg mockCfg()
   {

--
Gitblit v1.10.0