From 8e9e861649292af6d4bd55d228243cf115addc09 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 23 Sep 2011 19:42:56 +0000
Subject: [PATCH] Fix OPENDJ-292: LDAP PTA NPE when base-dn or bind-dn not exist on secondary server

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java |   79 +++++++++++++++++++++++++++++++++++++++
 opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java                          |   41 +++++++-------------
 2 files changed, 93 insertions(+), 27 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
index 270f87c..6968ca3 100644
--- a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
+++ b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
@@ -101,24 +101,17 @@
       {
         this.startIndex = nextIndex = startIndex;
 
-        DirectoryException lastException = null;
+        DirectoryException lastException;
         do
         {
           factory = factories[nextIndex];
-          if (factory.isAvailable())
+          if (factory.isAvailable)
           {
             try
             {
-              if (factory.isAvailable)
-              {
-                connection = factory.getConnection();
-                incrementNextIndex();
-                return;
-              }
-              else if (lastException == null)
-              {
-                lastException = factory.lastException;
-              }
+              connection = factory.getConnection();
+              incrementNextIndex();
+              return;
             }
             catch (final DirectoryException e)
             {
@@ -130,6 +123,10 @@
               lastException = e;
             }
           }
+          else
+          {
+            lastException = factory.lastException;
+          }
           incrementNextIndex();
         }
         while (nextIndex != startIndex);
@@ -222,16 +219,13 @@
         while (nextIndex != startIndex)
         {
           factory = factories[nextIndex];
-          if (factory.isAvailable())
+          if (factory.isAvailable)
           {
             try
             {
-              if (factory.isAvailable)
-              {
-                connection = factory.getConnection();
-                incrementNextIndex();
-                return;
-              }
+              connection = factory.getConnection();
+              incrementNextIndex();
+              return;
             }
             catch (final DirectoryException de)
             {
@@ -319,13 +313,6 @@
           throw e;
         }
       }
-
-
-
-      private boolean isAvailable()
-      {
-        return isAvailable;
-      }
     }
 
 
@@ -397,7 +384,7 @@
     {
       for (final MonitoredConnectionFactory factory : factories)
       {
-        if (!factory.isAvailable())
+        if (!factory.isAvailable)
         {
           try
           {
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 d1f57da..9324b53 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
@@ -3720,6 +3720,85 @@
 
 
 
+  /**
+   * Test for issue OPENDJ-292 (https://bugster.forgerock.org/jira/browse/OPENDJ-292).
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testIssueOPENDJ292() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg()
+        .withPrimaryServer(phost1)
+        .withSecondaryServer(shost1)
+        .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(
+        shost1, cfg);
+    provider.expectEvent(fe1).expectEvent(fe2);
+
+    // Get connection for phost1, then search, then bind.
+    final GetConnectionEvent ceSearch1 = new GetConnectionEvent(fe1,
+        ResultCode.CLIENT_SIDE_CONNECT_ERROR);
+    final GetConnectionEvent ceSearch2 = new GetConnectionEvent(fe2);
+
+    provider
+        .expectEvent(ceSearch1)
+        .expectEvent(ceSearch2)
+        .expectEvent(
+            new SimpleBindEvent(ceSearch2, searchBindDNString,
+                "searchPassword", ResultCode.INVALID_CREDENTIALS))
+        .expectEvent(new CloseEvent(ceSearch2));
+
+    // 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);
+
+    // Authenticate twice, the second time was causing a NPE because none of the
+    // factories were available and an attempt was made to throw a null
+    // exception.
+    final AuthenticationPolicyState state = policy
+        .createAuthenticationPolicyState(userEntry);
+    assertEquals(state.getAuthenticationPolicy(), policy);
+
+    // Perform authentication.
+    for (int i = 0; i < 2; i++)
+    {
+      try
+      {
+        state.passwordMatches(ByteString.valueOf(userPassword));
+        fail("password match unexpectedly succeeded");
+      }
+      catch (final DirectoryException e)
+      {
+        // No mapping attributes so this should always fail with
+        // INVALID_CREDENTIALS.
+        assertEquals(e.getResultCode(), ResultCode.INVALID_CREDENTIALS,
+            e.getMessage());
+      }
+      state.finalizeStateAfterBind();
+    }
+
+    // Tear down and check final state.
+    policy.finalizeAuthenticationPolicy();
+    provider.assertAllExpectedEventsReceived();
+  }
+
+
+
   // TODO: detect when servers come back online
 
   MockPolicyCfg mockCfg()

--
Gitblit v1.10.0