From c8cbf831d0d3fe5ab522a7426081374ca1a148bb Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 27 Sep 2011 16:35:18 +0000
Subject: [PATCH] Fix OPENDJ-290: LDAP PTA valid auth attempt rejected if AD reset connection

---
 opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java |  100 ++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 77 insertions(+), 23 deletions(-)

diff --git a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
index dc8d1e5..8dece5f 100644
--- a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
+++ b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
@@ -74,8 +74,7 @@
   // TODO: handle password policy response controls? AD?
   // TODO: custom aliveness pings
   // TODO: cache password
-  // TODO: handle idle timeouts (connection resets): implement retry logic in
-  // connection pools.
+  // TODO: improve debug logging and error messages.
 
   /**
    * A simplistic load-balancer connection factory implementation using
@@ -591,7 +590,7 @@
      */
     private final class PooledConnection implements Connection
     {
-      private final Connection connection;
+      private Connection connection;
       private boolean connectionIsClosed = false;
 
 
@@ -622,6 +621,8 @@
           {
             connectionPool.offer(connection);
           }
+
+          connection = null;
           availableConnections.release();
         }
       }
@@ -639,11 +640,25 @@
         {
           return connection.search(baseDN, scope, filter);
         }
-        catch (final DirectoryException e)
+        catch (final DirectoryException e1)
         {
-          // Don't put the connection back in the pool if it has failed.
-          closeConnectionIfServiceError(e);
-          throw e;
+          // Fail immediately if the result indicates that the operation failed
+          // for a reason other than connection/server failure.
+          reconnectIfConnectionFailure(e1);
+
+          // The connection has failed, so retry the operation using the new
+          // connection.
+          try
+          {
+            return connection.search(baseDN, scope, filter);
+          }
+          catch (final DirectoryException e2)
+          {
+            // If the connection has failed again then give up: don't put the
+            // connection back in the pool.
+            closeIfConnectionFailure(e2);
+            throw e2;
+          }
         }
       }
 
@@ -660,29 +675,68 @@
         {
           connection.simpleBind(username, password);
         }
-        catch (final DirectoryException e)
+        catch (final DirectoryException e1)
         {
-          // Don't put the connection back in the pool if it has failed.
-          closeConnectionIfServiceError(e);
-          throw e;
-        }
-      }
+          // Fail immediately if the result indicates that the operation failed
+          // for a reason other than connection/server failure.
+          reconnectIfConnectionFailure(e1);
 
-
-
-      private void closeConnectionIfServiceError(final DirectoryException e)
-      {
-        if (isServiceError(e.getResultCode()))
-        {
-          if (!connectionIsClosed)
+          // The connection has failed, so retry the operation using the new
+          // connection.
+          try
           {
-            connectionIsClosed = true;
-            connection.close();
-            availableConnections.release();
+            connection.simpleBind(username, password);
+          }
+          catch (final DirectoryException e2)
+          {
+            // If the connection has failed again then give up: don't put the
+            // connection back in the pool.
+            closeIfConnectionFailure(e2);
+            throw e2;
           }
         }
       }
 
+
+
+      private void closeIfConnectionFailure(final DirectoryException e)
+          throws DirectoryException
+      {
+        if (isServiceError(e.getResultCode()))
+        {
+          connectionIsClosed = true;
+          connection.close();
+          connection = null;
+          availableConnections.release();
+        }
+      }
+
+
+
+      private void reconnectIfConnectionFailure(final DirectoryException e)
+          throws DirectoryException
+      {
+        if (!isServiceError(e.getResultCode()))
+        {
+          throw e;
+        }
+
+        // The connection has failed (e.g. idle timeout), so repeat the
+        // request on a new connection.
+        connection.close();
+        try
+        {
+          connection = factory.getConnection();
+        }
+        catch (final DirectoryException e2)
+        {
+          // Give up - the server is unreachable.
+          connectionIsClosed = true;
+          connection = null;
+          availableConnections.release();
+          throw e2;
+        }
+      }
     }
 
 

--
Gitblit v1.10.0