mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
19.34.2011 15cd2536d46692eb2a770804b0597142f3efed19
Issue OPENDJ-262: Implement pass through authentication (PTA)

Ensure that all result codes returned in a disconnect notification are mapped to a "connection failure" error code.
3 files modified
61 ■■■■■ changed files
opends/src/messages/messages/extension.properties 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java 49 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java 10 ●●●● patch | view | raw | blame | history
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"
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:
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));
    }