From 3235ccd26fe404f9871618246bf4bec58d908545 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 19 Sep 2011 15:34:26 +0000
Subject: [PATCH] Issue OPENDJ-262: Implement pass through authentication (PTA)

---
 opendj-sdk/opends/src/messages/messages/extension.properties                                                                       |    2 
 opendj-sdk/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java                          |   49 +++++++++++++++++-------
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java |   10 ++--
 3 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/opendj-sdk/opends/src/messages/messages/extension.properties b/opendj-sdk/opends/src/messages/messages/extension.properties
index cbde8c7..edd2010 100644
--- a/opendj-sdk/opends/src/messages/messages/extension.properties
+++ b/opendj-sdk/opends/src/messages/messages/extension.properties
@@ -1482,7 +1482,7 @@
  from the server and will be closed. The unexpected response message was: %s
 MILD_ERR_LDAP_PTA_CONNECTION_DISCONNECTING_601=The connection to the remote LDAP \
  server at %s:%d for LDAP PTA policy "%s" has received a disconnect notification \
- from the server and will be closed: %s
+ with response code %d (%s) and error message "%s"
 MILD_ERR_LDAP_PTA_CONNECTION_BIND_FAILED_602=The remote LDAP server at %s:%d \
  for LDAP PTA policy "%s" has failed to authenticate user "%s", returning the \
  response code %d (%s) and error message "%s"
diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
index 1b32e4c..02702cd 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
@@ -202,7 +202,7 @@
       {
         // If the error does not indicate that the connection has failed, then
         // pass this back to the caller.
-        if (!isFatalResultCode(e.getResultCode()))
+        if (!isServiceError(e.getResultCode()))
         {
           throw e;
         }
@@ -643,7 +643,7 @@
         catch (final DirectoryException e)
         {
           // Don't put the connection back in the pool if it has failed.
-          closeConnectionOnFatalError(e);
+          closeConnectionIfServiceError(e);
           throw e;
         }
       }
@@ -664,16 +664,16 @@
         catch (final DirectoryException e)
         {
           // Don't put the connection back in the pool if it has failed.
-          closeConnectionOnFatalError(e);
+          closeConnectionIfServiceError(e);
           throw e;
         }
       }
 
 
 
-      private void closeConnectionOnFatalError(final DirectoryException e)
+      private void closeConnectionIfServiceError(final DirectoryException e)
       {
-        if (isFatalResultCode(e.getResultCode()))
+        if (isServiceError(e.getResultCode()))
         {
           if (!connectionIsClosed)
           {
@@ -1097,10 +1097,28 @@
           if ((responseOID != null)
               && responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
           {
-            throw new DirectoryException(ResultCode.valueOf(extendedResponse
-                .getResultCode()), ERR_LDAP_PTA_CONNECTION_DISCONNECTING.get(
-                host, port, String.valueOf(cfg.dn()),
-                extendedResponse.getErrorMessage()));
+            ResultCode resultCode = ResultCode.valueOf(extendedResponse
+                .getResultCode());
+
+            /*
+             * Since the connection has been disconnected we want to ensure that
+             * upper layers treat all disconnect notifications as fatal and
+             * close the connection. Therefore we map the result code to a fatal
+             * error code if needed. A good example of a non-fatal error code
+             * being returned is INVALID_CREDENTIALS which is used to indicate
+             * that the currently bound user has had their entry removed. We
+             * definitely don't want to pass this straight back to the caller
+             * since it will be misinterpreted as an authentication failure if
+             * the operation being performed is a bind.
+             */
+            ResultCode mappedResultCode = isServiceError(resultCode) ?
+                resultCode : ResultCode.UNAVAILABLE;
+
+            throw new DirectoryException(mappedResultCode,
+                ERR_LDAP_PTA_CONNECTION_DISCONNECTING.get(host, port,
+                    String.valueOf(cfg.dn()), resultCode.getIntValue(),
+                    resultCode.getResultCodeName(),
+                    extendedResponse.getErrorMessage()));
           }
         }
 
@@ -2052,17 +2070,20 @@
    * @return {@code true} if the result code is expected to trigger the
    *         associated connection to be closed immediately.
    */
-  static boolean isFatalResultCode(final ResultCode resultCode)
+  static boolean isServiceError(final ResultCode resultCode)
   {
     switch (resultCode)
     {
+    case OPERATIONS_ERROR:
+    case PROTOCOL_ERROR:
+    case TIME_LIMIT_EXCEEDED:
+    case ADMIN_LIMIT_EXCEEDED:
+    case UNAVAILABLE_CRITICAL_EXTENSION:
     case BUSY:
     case UNAVAILABLE:
-    case PROTOCOL_ERROR:
-    case OTHER:
     case UNWILLING_TO_PERFORM:
-    case OPERATIONS_ERROR:
-    case TIME_LIMIT_EXCEEDED:
+    case LOOP_DETECT:
+    case OTHER:
     case CLIENT_SIDE_CONNECT_ERROR:
     case CLIENT_SIDE_DECODING_ERROR:
     case CLIENT_SIDE_ENCODING_ERROR:
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
index 62d697a..e750ecb 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
@@ -28,7 +28,7 @@
 
 
 
-import static org.opends.server.extensions.LDAPPassThroughAuthenticationPolicyFactory.isFatalResultCode;
+import static org.opends.server.extensions.LDAPPassThroughAuthenticationPolicyFactory.isServiceError;
 import static org.opends.server.protocols.ldap.LDAPConstants.OID_NOTICE_OF_DISCONNECTION;
 import static org.testng.Assert.*;
 
@@ -1534,7 +1534,7 @@
         .expectEvent(
             new SearchEvent(ceSearch, "o=ad", SearchScope.WHOLE_SUBTREE,
                 "(uid=aduser)", searchResultCode));
-    if (isFatalResultCode(searchResultCode))
+    if (isServiceError(searchResultCode))
     {
       // The connection will fail and be closed immediately.
       provider.expectEvent(new CloseEvent(ceSearch));
@@ -1568,7 +1568,7 @@
     state.finalizeStateAfterBind();
 
     // Cached connections should be closed when the policy is finalized.
-    if (!isFatalResultCode(searchResultCode))
+    if (!isServiceError(searchResultCode))
     {
       provider.expectEvent(new CloseEvent(ceSearch));
     }
@@ -3234,7 +3234,7 @@
         new SimpleBindEvent(ceBind,
             mappingPolicy == MappingPolicy.UNMAPPED ? opendjDNString
                 : adDNString, userPassword, bindResultCode));
-    if (isFatalResultCode(bindResultCode))
+    if (isServiceError(bindResultCode))
     {
       // The connection will fail and be closed immediately.
       provider.expectEvent(new CloseEvent(ceBind));
@@ -3286,7 +3286,7 @@
     {
       provider.expectEvent(new CloseEvent(ceSearch));
     }
-    if (!isFatalResultCode(bindResultCode))
+    if (!isServiceError(bindResultCode))
     {
       provider.expectEvent(new CloseEvent(ceBind));
     }

--
Gitblit v1.10.0